aboutsummaryrefslogtreecommitdiffstats
path: root/Source/charon/sa
diff options
context:
space:
mode:
Diffstat (limited to 'Source/charon/sa')
-rw-r--r--Source/charon/sa/child_sa.c301
-rw-r--r--Source/charon/sa/child_sa.h7
-rw-r--r--Source/charon/sa/ike_sa.c25
-rw-r--r--Source/charon/sa/ike_sa.h11
-rw-r--r--Source/charon/sa/states/ike_auth_requested.c52
-rw-r--r--Source/charon/sa/states/ike_auth_requested.h6
-rw-r--r--Source/charon/sa/states/ike_sa_init_requested.c31
-rw-r--r--Source/charon/sa/states/ike_sa_init_responded.c22
8 files changed, 381 insertions, 74 deletions
diff --git a/Source/charon/sa/child_sa.c b/Source/charon/sa/child_sa.c
index 2c4624310..6754e8022 100644
--- a/Source/charon/sa/child_sa.c
+++ b/Source/charon/sa/child_sa.c
@@ -39,14 +39,29 @@ struct private_child_sa_t {
child_sa_t public;
/**
- * CHILD_SAs own logger
+ * IP of this peer
*/
- logger_t *logger;
+ host_t *me;
/**
- * Protocols used in this SA
+ * IP of other peer
*/
- protocol_id_t protocols[2];
+ host_t *other;
+
+ /**
+ * Security parameter index for AH protocol, 0 if not used
+ */
+ u_int32_t ah_spi;
+
+ /**
+ * Security parameter index for ESP protocol, 0 if not used
+ */
+ u_int32_t esp_spi;
+
+ /**
+ * CHILD_SAs own logger
+ */
+ logger_t *logger;
};
@@ -59,65 +74,271 @@ static u_int32_t get_spi(private_child_sa_t *this)
}
/**
- * Implementation of child_sa_t.destroy.
+ * Implements child_sa_t.alloc
*/
-static void destroy(private_child_sa_t *this)
+static status_t alloc(private_child_sa_t *this, linked_list_t *proposals)
{
- charon->logger_manager->destroy_logger(charon->logger_manager, this->logger);
- allocator_free(this);
+ protocol_id_t protocols[2];
+ iterator_t *iterator;
+ proposal_t *proposal;
+ status_t status;
+ u_int i;
+
+ /* iterator through proposals */
+ iterator = proposals->create_iterator(proposals, TRUE);
+ while(iterator->has_next(iterator))
+ {
+ iterator->current(iterator, (void**)&proposal);
+ proposal->get_protocols(proposal, protocols);
+
+ /* check all protocols */
+ for (i = 0; i<2; i++)
+ {
+ switch (protocols[i])
+ {
+ case AH:
+ /* do we already have an spi for AH?*/
+ if (this->ah_spi == 0)
+ {
+ /* nope, get one */
+ status = charon->kernel_interface->get_spi(
+ charon->kernel_interface,
+ this->me, this->other,
+ AH, FALSE,
+ &(this->ah_spi));
+ }
+ /* update proposal */
+ proposal->set_spi(proposal, AH, (u_int64_t)this->ah_spi);
+ break;
+ case ESP:
+ /* do we already have an spi for ESP?*/
+ if (this->esp_spi == 0)
+ {
+ /* nope, get one */
+ status = charon->kernel_interface->get_spi(
+ charon->kernel_interface,
+ this->me, this->other,
+ ESP, FALSE,
+ &(this->esp_spi));
+ }
+ /* update proposal */
+ proposal->set_spi(proposal, ESP, (u_int64_t)this->esp_spi);
+ break;
+ default:
+ break;
+ }
+ if (status != SUCCESS)
+ {
+ iterator->destroy(iterator);
+ return FAILED;
+ }
+ }
+ }
+ iterator->destroy(iterator);
+ return SUCCESS;
}
-/*
- * Described in header.
- */
-child_sa_t * child_sa_create(proposal_t *proposal, prf_plus_t *prf_plus)
+static status_t install(private_child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus, bool mine)
{
- private_child_sa_t *this = allocator_alloc_thing(private_child_sa_t);
+ protocol_id_t protocols[2];
+ u_int32_t spi;
+ encryption_algorithm_t enc_algo;
+ integrity_algorithm_t int_algo;
+ chunk_t enc_key, int_key;
+ algorithm_t *algo;
+ crypter_t *crypter;
+ signer_t *signer;
+ size_t key_size;
+ host_t *src;
+ host_t *dst;
+ status_t status;
u_int i;
-
- /* public functions */
- this->public.get_spi = (u_int32_t(*)(child_sa_t*))get_spi;
- this->public.destroy = (void(*)(child_sa_t*))destroy;
-
- /* private data */
- this->logger = charon->logger_manager->create_logger(charon->logger_manager, CHILD_SA, NULL);
- proposal->get_protocols(proposal, this->protocols);
- /* derive keys */
+ /* we must assign the roles to correctly set up the SAs */
+ if (mine)
+ {
+ src = this->me;
+ dst = this->other;
+ }
+ else
+ {
+ dst = this->me;
+ src = this->other;
+ }
+
+ proposal->get_protocols(proposal, protocols);
+ /* derive keys in order as protocols appear */
for (i = 0; i<2; i++)
{
- if (this->protocols[i] != UNDEFINED_PROTOCOL_ID)
+ if (protocols[i] != UNDEFINED_PROTOCOL_ID)
{
- algorithm_t *algo;
- chunk_t key;
- /* get encryption key */
- if (proposal->get_algorithm(proposal, this->protocols[i], ENCRYPTION_ALGORITHM, &algo))
+ /* now we have to decide which spi to use. Use self allocated, if "mine",
+ * or the one in the proposal, if not "mine" (others). */
+ if (mine)
+ {
+ if (protocols[i] == AH)
+ {
+ spi = this->ah_spi;
+ }
+ else
+ {
+ spi = this->esp_spi;
+ }
+ }
+ else /* use proposals spi */
+ {
+ spi = proposal->get_spi(proposal, protocols[i]);
+ }
+
+ /* derive encryption key first */
+ if (proposal->get_algorithm(proposal, protocols[i], ENCRYPTION_ALGORITHM, &algo))
{
- this->logger->log(this->logger, CONTROL|LEVEL1, "%s: using %s %s, ",
- mapping_find(protocol_id_m, this->protocols[i]),
+ enc_algo = algo->algorithm;
+ this->logger->log(this->logger, CONTROL|LEVEL1, "%s for %s: using %s %s, ",
+ mapping_find(protocol_id_m, protocols[i]),
+ mine ? "me" : "other",
mapping_find(transform_type_m, ENCRYPTION_ALGORITHM),
- mapping_find(encryption_algorithm_m, algo->algorithm));
+ mapping_find(encryption_algorithm_m, enc_algo));
- prf_plus->allocate_bytes(prf_plus, algo->key_size, &key);
- this->logger->log_chunk(this->logger, PRIVATE, "key:", &key);
- allocator_free_chunk(&key);
+ /* we must create a (unused) crypter, since its the only way to get the size
+ * of the key. This is not so nice, since charon must support all algorithms
+ * the kernel supports...
+ * TODO: build something of a encryption algorithm lookup function
+ */
+ crypter = crypter_create(enc_algo, algo->key_size);
+ key_size = crypter->get_key_size(crypter);
+ crypter->destroy(crypter);
+ prf_plus->allocate_bytes(prf_plus, key_size, &enc_key);
+ this->logger->log_chunk(this->logger, PRIVATE, "key:", &enc_key);
+ }
+ else
+ {
+ enc_algo = ENCR_UNDEFINED;
}
- /* get integrity key */
- if (proposal->get_algorithm(proposal, this->protocols[i], INTEGRITY_ALGORITHM, &algo))
+ /* derive integrity key */
+ if (proposal->get_algorithm(proposal, protocols[i], INTEGRITY_ALGORITHM, &algo))
{
- this->logger->log(this->logger, CONTROL|LEVEL1, "%s: using %s %s,",
- mapping_find(protocol_id_m, this->protocols[i]),
+ int_algo = algo->algorithm;
+ this->logger->log(this->logger, CONTROL|LEVEL1, "%s for %s: using %s %s,",
+ mapping_find(protocol_id_m, protocols[i]),
+ mine ? "me" : "other",
mapping_find(transform_type_m, INTEGRITY_ALGORITHM),
mapping_find(integrity_algorithm_m, algo->algorithm));
- prf_plus->allocate_bytes(prf_plus, algo->key_size, &key);
- this->logger->log_chunk(this->logger, PRIVATE, "key:", &key);
- allocator_free_chunk(&key);
+ signer = signer_create(int_algo);
+ key_size = signer->get_key_size(signer);
+ signer->destroy(signer);
+ prf_plus->allocate_bytes(prf_plus, key_size, &int_key);
+ this->logger->log_chunk(this->logger, PRIVATE, "key:", &int_key);
+ }
+ else
+ {
+ int_algo = AUTH_UNDEFINED;
+ }
+ /* send keys down to kernel */
+ this->logger->log(this->logger, CONTROL|LEVEL1,
+ "installing 0x%.8x for %s, src %s dst %s",
+ ntohl(spi), mapping_find(protocol_id_m, protocols[i]),
+ src->get_address(src), dst->get_address(dst));
+ status = charon->kernel_interface->add_sa(charon->kernel_interface,
+ src, dst,
+ spi, protocols[i], FALSE,
+ enc_algo, enc_key,
+ int_algo, int_key, mine);
+ /* clean up for next round */
+ if (enc_algo != ENCR_UNDEFINED)
+ {
+ allocator_free_chunk(&enc_key);
}
+ if (int_algo != AUTH_UNDEFINED)
+ {
+ allocator_free_chunk(&int_key);
+ }
+
+ if (status != SUCCESS)
+ {
+ return FAILED;
+ }
+
}
}
+ return SUCCESS;
+}
+
+static status_t add(private_child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus)
+{
+ linked_list_t *list;
+
+ /* install others (initiators) SAs*/
+ if (install(this, proposal, prf_plus, FALSE) != SUCCESS)
+ {
+ return FAILED;
+ }
+
+ /* get SPIs for our SAs */
+ list = linked_list_create();
+ list->insert_last(list, proposal);
+ if (alloc(this, list) != SUCCESS)
+ {
+ list->destroy(list);
+ return FAILED;
+ }
+ list->destroy(list);
+
+ /* install our (responders) SAs */
+ if (install(this, proposal, prf_plus, TRUE) != SUCCESS)
+ {
+ return FAILED;
+ }
+ return SUCCESS;
+}
+
+static status_t update(private_child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus)
+{
+ /* install our (initator) SAs */
+ if (install(this, proposal, prf_plus, TRUE) != SUCCESS)
+ {
+ return FAILED;
+ }
+ /* install his (responder) SAs */
+ if (install(this, proposal, prf_plus, FALSE) != SUCCESS)
+ {
+ return FAILED;
+ }
+ return SUCCESS;
+}
+
+/**
+ * Implementation of child_sa_t.destroy.
+ */
+static void destroy(private_child_sa_t *this)
+{
+ charon->logger_manager->destroy_logger(charon->logger_manager, this->logger);
+ allocator_free(this);
+}
+
+/*
+ * Described in header.
+ */
+child_sa_t * child_sa_create(host_t *me, host_t* other)
+{
+ private_child_sa_t *this = allocator_alloc_thing(private_child_sa_t);
+
+ /* public functions */
+ this->public.get_spi = (u_int32_t(*)(child_sa_t*))get_spi;
+ this->public.alloc = (status_t(*)(child_sa_t*,linked_list_t*))alloc;
+ 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.destroy = (void(*)(child_sa_t*))destroy;
+
+ /* private data */
+ this->logger = charon->logger_manager->create_logger(charon->logger_manager, CHILD_SA, NULL);
+ this->me = me;
+ this->other = other;
+ this->ah_spi = 0;
+ this->esp_spi = 0;
return (&this->public);
}
diff --git a/Source/charon/sa/child_sa.h b/Source/charon/sa/child_sa.h
index bde032b74..260c4f29c 100644
--- a/Source/charon/sa/child_sa.h
+++ b/Source/charon/sa/child_sa.h
@@ -50,6 +50,11 @@ struct child_sa_t {
* @return 4 Byte SPI value
*/
u_int32_t (*get_spi) (child_sa_t *this);
+
+
+ status_t (*alloc)(child_sa_t *this, linked_list_t* proposals);
+ status_t (*add)(child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus);
+ status_t (*update)(child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus);
/**
* @brief Destroys a child_sa.
@@ -67,6 +72,6 @@ struct child_sa_t {
* @return child_sa_t object
* @ingroup sa
*/
-child_sa_t * child_sa_create(proposal_t *proposal, prf_plus_t *prf_plus);
+child_sa_t * child_sa_create(host_t *me, host_t *other);
#endif /*_CHILD_SA_H_*/
diff --git a/Source/charon/sa/ike_sa.c b/Source/charon/sa/ike_sa.c
index ac617faef..55c03ef92 100644
--- a/Source/charon/sa/ike_sa.c
+++ b/Source/charon/sa/ike_sa.c
@@ -417,7 +417,7 @@ status_t retransmit_request (private_ike_sa_t *this, u_int32_t message_id)
*/
static void set_new_state (private_ike_sa_t *this, state_t *state)
{
- this->logger->log(this->logger, CONTROL, "Change current state %s to %s",
+ this->logger->log(this->logger, CONTROL, "statechange: %s => %s",
mapping_find(ike_sa_state_m,this->current_state->get_state(this->current_state)),
mapping_find(ike_sa_state_m,state->get_state(state)));
this->current_state = state;
@@ -964,6 +964,14 @@ static ike_sa_state_t get_state (private_ike_sa_t *this)
}
/**
+ * Implementation of protected_ike_sa_t.get_state.
+ */
+static void add_child_sa (private_ike_sa_t *this, child_sa_t *child_sa)
+{
+ this->child_sas->insert_last(this->child_sas, child_sa);
+}
+
+/**
* Implementation of protected_ike_sa_t.reset_message_buffers.
*/
static void reset_message_buffers (private_ike_sa_t *this)
@@ -1008,21 +1016,17 @@ static void create_delete_established_ike_sa_job (private_ike_sa_t *this,u_int32
*/
static void destroy (private_ike_sa_t *this)
{
+ child_sa_t *child_sa;
+
this->logger->log(this->logger, CONTROL|LEVEL2, "Going to destroy IKE SA %llu:%llu, role %s",
this->ike_sa_id->get_initiator_spi(this->ike_sa_id),
this->ike_sa_id->get_responder_spi(this->ike_sa_id),
this->ike_sa_id->is_initiator(this->ike_sa_id) ? "initiator" : "responder");
/* destroy child sa's */
- this->logger->log(this->logger, CONTROL | LEVEL3, "Destroy all child_sa's");
- while (this->child_sas->get_count(this->child_sas) > 0)
+ while (this->child_sas->remove_last(this->child_sas, (void**)&child_sa) == SUCCESS)
{
- void *child_sa;
- if (this->child_sas->remove_first(this->child_sas, &child_sa) != SUCCESS)
- {
- break;
- }
- /* destroy child sa */
+ child_sa->destroy(child_sa);
}
this->child_sas->destroy(this->child_sas);
@@ -1134,7 +1138,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
this->protected.get_child_prf = (prf_t *(*) (protected_ike_sa_t *)) get_child_prf;
this->protected.get_prf_auth_i = (prf_t *(*) (protected_ike_sa_t *)) get_prf_auth_i;
this->protected.get_prf_auth_r = (prf_t *(*) (protected_ike_sa_t *)) get_prf_auth_r;
- this->protected.get_logger = (logger_t *(*) (protected_ike_sa_t *)) get_logger;
+ this->protected.add_child_sa = (void (*) (protected_ike_sa_t*,child_sa_t*)) add_child_sa;
+ this->protected.get_logger = (logger_t *(*) (protected_ike_sa_t *)) get_logger;
this->protected.set_init_config = (void (*) (protected_ike_sa_t *,init_config_t *)) set_init_config;
this->protected.get_init_config = (init_config_t *(*) (protected_ike_sa_t *)) get_init_config;
this->protected.set_sa_config = (void (*) (protected_ike_sa_t *,sa_config_t *)) set_sa_config;
diff --git a/Source/charon/sa/ike_sa.h b/Source/charon/sa/ike_sa.h
index f5591a00b..b15a8eaab 100644
--- a/Source/charon/sa/ike_sa.h
+++ b/Source/charon/sa/ike_sa.h
@@ -27,10 +27,11 @@
#include <encoding/message.h>
#include <encoding/payloads/proposal_substructure.h>
#include <sa/ike_sa_id.h>
+#include <sa/child_sa.h>
+#include <sa/states/state.h>
#include <config/configuration_manager.h>
#include <utils/logger.h>
#include <utils/randomizer.h>
-#include <sa/states/state.h>
#include <transforms/prfs/prf.h>
#include <transforms/crypters/crypter.h>
#include <transforms/signers/signer.h>
@@ -388,6 +389,14 @@ struct protected_ike_sa_t {
prf_t *(*get_prf_auth_r) (protected_ike_sa_t *this);
/**
+ * @brief Associates a child SA to this IKE SA
+ *
+ * @param this calling object
+ * @param child_sa child_sa to add
+ */
+ void (*add_child_sa) (protected_ike_sa_t *this, child_sa_t *child_sa);
+
+ /**
* @brief Get the last responded message.
*
* @param this calling object
diff --git a/Source/charon/sa/states/ike_auth_requested.c b/Source/charon/sa/states/ike_auth_requested.c
index e6559319c..328971579 100644
--- a/Source/charon/sa/states/ike_auth_requested.c
+++ b/Source/charon/sa/states/ike_auth_requested.c
@@ -71,6 +71,11 @@ struct private_ike_auth_requested_t {
* IKE_SA_INIT-Request in binary form.
*/
chunk_t ike_sa_init_reply_data;
+
+ /**
+ * Child sa created in ike_sa_init_requested
+ */
+ child_sa_t *child_sa;
/**
* Assigned Logger.
@@ -136,6 +141,16 @@ struct private_ike_auth_requested_t {
* - DELETE_ME
*/
status_t (*process_notify_payload) (private_ike_auth_requested_t *this, notify_payload_t *notify_payload);
+
+ /**
+ * Destroy function called internally of this class after state change to
+ * state IKE_SA_ESTABLISHED succeeded.
+ *
+ * This destroy function does not destroy objects which were passed to the new state.
+ *
+ * @param this calling object
+ */
+ void (*destroy_after_state_change) (private_ike_auth_requested_t *this);
};
@@ -288,7 +303,7 @@ static status_t process_message(private_ike_auth_requested_t *this, message_t *i
this->ike_sa->create_delete_established_ike_sa_job(this->ike_sa,this->sa_config->get_ike_sa_lifetime(this->sa_config));
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));
+ this->destroy_after_state_change(this);
return SUCCESS;
}
@@ -328,7 +343,6 @@ static status_t process_sa_payload(private_ike_auth_requested_t *this, sa_payloa
{
proposal_t *proposal, *proposal_tmp;
linked_list_t *proposal_list;
- child_sa_t *child_sa;
chunk_t seed;
prf_plus_t *prf_plus;
@@ -377,10 +391,19 @@ static status_t process_sa_payload(private_ike_auth_requested_t *this, sa_payloa
prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed);
allocator_free_chunk(&seed);
- child_sa = child_sa_create(proposal, prf_plus);
- prf_plus->destroy(prf_plus);
- child_sa->destroy(child_sa);
+ if (this->child_sa)
+ {
+ if (this->child_sa->update(this->child_sa, proposal, prf_plus) != SUCCESS)
+ {
+ this->logger->log(this->logger, AUDIT, "Could not install CHILD_SA! Deleting IKE_SA");
+ prf_plus->destroy(prf_plus);
+ proposal->destroy(proposal);
+ return DELETE_ME;
+ }
+ this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
+ }
+ prf_plus->destroy(prf_plus);
proposal->destroy(proposal);
return SUCCESS;
@@ -524,6 +547,20 @@ static void destroy(private_ike_auth_requested_t *this)
{
allocator_free_chunk(&(this->received_nonce));
allocator_free_chunk(&(this->sent_nonce));
+ allocator_free_chunk(&(this->ike_sa_init_reply_data));
+ if (this->child_sa)
+ {
+ this->child_sa->destroy(this->child_sa);
+ }
+ allocator_free(this);
+}
+/**
+ * Implements protected_ike_sa_t.destroy_after_state_change
+ */
+static void destroy_after_state_change(private_ike_auth_requested_t *this)
+{
+ allocator_free_chunk(&(this->received_nonce));
+ allocator_free_chunk(&(this->sent_nonce));
allocator_free_chunk(&(this->ike_sa_init_reply_data));
allocator_free(this);
}
@@ -531,7 +568,7 @@ static void destroy(private_ike_auth_requested_t *this)
/*
* Described in header.
*/
-ike_auth_requested_t *ike_auth_requested_create(protected_ike_sa_t *ike_sa,chunk_t sent_nonce,chunk_t received_nonce,chunk_t ike_sa_init_reply_data)
+ike_auth_requested_t *ike_auth_requested_create(protected_ike_sa_t *ike_sa,chunk_t sent_nonce,chunk_t received_nonce,chunk_t ike_sa_init_reply_data, child_sa_t *child_sa)
{
private_ike_auth_requested_t *this = allocator_alloc_thing(private_ike_auth_requested_t);
@@ -541,12 +578,12 @@ ike_auth_requested_t *ike_auth_requested_create(protected_ike_sa_t *ike_sa,chunk
this->public.state_interface.destroy = (void (*) (state_t *)) destroy;
/* private functions */
-
this->process_idr_payload = process_idr_payload;
this->process_sa_payload = process_sa_payload;
this->process_auth_payload = process_auth_payload;
this->process_ts_payload = process_ts_payload;
this->process_notify_payload = process_notify_payload;
+ this->destroy_after_state_change = destroy_after_state_change;
/* private data */
this->ike_sa = ike_sa;
@@ -554,6 +591,7 @@ ike_auth_requested_t *ike_auth_requested_create(protected_ike_sa_t *ike_sa,chunk
this->sent_nonce = sent_nonce;
this->ike_sa_init_reply_data = ike_sa_init_reply_data;
this->logger = this->ike_sa->get_logger(this->ike_sa);
+ this->child_sa = child_sa;
return &(this->public);
}
diff --git a/Source/charon/sa/states/ike_auth_requested.h b/Source/charon/sa/states/ike_auth_requested.h
index 34b948856..a8eef014c 100644
--- a/Source/charon/sa/states/ike_auth_requested.h
+++ b/Source/charon/sa/states/ike_auth_requested.h
@@ -41,8 +41,6 @@ typedef struct ike_auth_requested_t ike_auth_requested_t;
*
* @todo handle certificate payloads
*
- * @todo setup child SAs, if requested
- *
* @ingroup states
*/
struct ike_auth_requested_t {
@@ -60,6 +58,7 @@ struct ike_auth_requested_t {
* @param sent_nonce Sent nonce value in IKE_SA_INIT request
* @param received_nonce Received nonce value in IKE_SA_INIT response
* @param ike_sa_init_reply_data binary representation of IKE_SA_INIT reply
+ * @param child_sa opened but not completed child_sa
* @return created ike_auth_requested_t object
*
* @ingroup states
@@ -67,6 +66,7 @@ struct ike_auth_requested_t {
ike_auth_requested_t *ike_auth_requested_create(protected_ike_sa_t *ike_sa,
chunk_t sent_nonce,
chunk_t received_nonce,
- chunk_t ike_sa_init_reply_data);
+ chunk_t ike_sa_init_reply_data,
+ child_sa_t *child_sa);
#endif /*IKE_AUTH_REQUESTED_H_*/
diff --git a/Source/charon/sa/states/ike_sa_init_requested.c b/Source/charon/sa/states/ike_sa_init_requested.c
index 327eb2d7c..55f38883f 100644
--- a/Source/charon/sa/states/ike_sa_init_requested.c
+++ b/Source/charon/sa/states/ike_sa_init_requested.c
@@ -80,6 +80,11 @@ struct private_ike_sa_init_requested_t {
chunk_t ike_sa_init_request_data;
/**
+ * Created child sa, if any
+ */
+ child_sa_t *child_sa;
+
+ /**
* Assigned logger
*
* Is logger of ike_sa!
@@ -187,8 +192,6 @@ struct private_ike_sa_init_requested_t {
* Destroy function called internally of this class after state change to
* state IKE_AUTH_REQUESTED succeeded.
*
- * In case of state change to INITIATOR_INIT the default destroy function gets called.
- *
* This destroy function does not destroy objects which were passed to the new state.
*
* @param this calling object
@@ -383,7 +386,8 @@ static status_t process_message(private_ike_sa_init_requested_t *this, message_t
ike_sa_init_reply_data = ike_sa_init_reply->get_packet_data(ike_sa_init_reply);
/* state can now be changed */
- next_state = ike_auth_requested_create(this->ike_sa,this->sent_nonce,this->received_nonce,ike_sa_init_reply_data);
+ next_state = ike_auth_requested_create(this->ike_sa, this->sent_nonce, this->received_nonce,
+ ike_sa_init_reply_data, this->child_sa);
this->ike_sa->set_new_state(this->ike_sa,(state_t *) next_state);
this->destroy_after_state_change(this);
@@ -512,10 +516,22 @@ static status_t build_sa_payload (private_ike_sa_init_requested_t *this, message
/* get proposals form config, add to payload */
sa_config = this->ike_sa->get_sa_config(this->ike_sa);
proposal_list = sa_config->get_proposals(sa_config);
+ /* build child sa */
+ this->child_sa = child_sa_create(this->ike_sa->get_my_host(this->ike_sa),
+ this->ike_sa->get_other_host(this->ike_sa));
+ if (this->child_sa->alloc(this->child_sa, proposal_list) != SUCCESS)
+ {
+ this->logger->log(this->logger, AUDIT, "Could not install CHILD_SA! Deleting IKE_SA");
+ return DELETE_ME;
+ }
+
+ /* TODO:
+ * Huston, we've got a problem here. Since SPIs are stored in
+ * the proposal, and these proposals are shared across configs,
+ * there may be some threading issues... fix it!
+ */
sa_payload = sa_payload_create_from_proposal_list(proposal_list);
- /* TODO child sa stuff */
-
this->logger->log(this->logger, CONTROL|LEVEL2, "Add SA payload to message");
request->add_payload(request,(payload_t *) sa_payload);
@@ -705,6 +721,10 @@ static void destroy(private_ike_sa_init_requested_t *this)
allocator_free(this->sent_nonce.ptr);
allocator_free(this->received_nonce.ptr);
allocator_free_chunk(&(this->ike_sa_init_request_data));
+ if (this->child_sa)
+ {
+ this->child_sa->destroy(this->child_sa);
+ }
if (this->proposal)
{
this->proposal->destroy(this->proposal);
@@ -743,6 +763,7 @@ ike_sa_init_requested_t *ike_sa_init_requested_create(protected_ike_sa_t *ike_sa
this->diffie_hellman = diffie_hellman;
this->proposal = NULL;
this->sent_nonce = sent_nonce;
+ this->child_sa = NULL;
this->ike_sa_init_request_data = ike_sa_init_request_data;
return &(this->public);
diff --git a/Source/charon/sa/states/ike_sa_init_responded.c b/Source/charon/sa/states/ike_sa_init_responded.c
index 536041d0d..70baa5143 100644
--- a/Source/charon/sa/states/ike_sa_init_responded.c
+++ b/Source/charon/sa/states/ike_sa_init_responded.c
@@ -425,10 +425,6 @@ static status_t build_sa_payload(private_ike_sa_init_responded_t *this, sa_paylo
return DELETE_ME;
}
- /* create payload with selected propsal */
- sa_response = sa_payload_create_from_proposal(proposal);
- response->add_payload(response, (payload_t*)sa_response);
-
/* install child SAs for AH and esp */
seed = allocator_alloc_as_chunk(this->received_nonce.len + this->sent_nonce.len);
memcpy(seed.ptr, this->received_nonce.ptr, this->received_nonce.len);
@@ -436,10 +432,22 @@ static status_t build_sa_payload(private_ike_sa_init_responded_t *this, sa_paylo
prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed);
allocator_free_chunk(&seed);
- child_sa = child_sa_create(proposal, prf_plus);
- prf_plus->destroy(prf_plus);
- child_sa->destroy(child_sa);
+ child_sa = child_sa_create(this->ike_sa->get_my_host(this->ike_sa),
+ this->ike_sa->get_other_host(this->ike_sa));
+ if (child_sa->add(child_sa, proposal, prf_plus) != SUCCESS)
+ {
+ this->logger->log(this->logger, AUDIT, "Could not install CHILD_SA! Deleting IKE_SA");
+ prf_plus->destroy(prf_plus);
+ proposal->destroy(proposal);
+ return DELETE_ME;
+ }
+ this->ike_sa->add_child_sa(this->ike_sa, child_sa);
+
+ /* create payload with selected propsal */
+ sa_response = sa_payload_create_from_proposal(proposal);
+ response->add_payload(response, (payload_t*)sa_response);
+ prf_plus->destroy(prf_plus);
proposal->destroy(proposal);
return SUCCESS;
}