aboutsummaryrefslogtreecommitdiffstats
path: root/src/charon/sa/child_sa.c
diff options
context:
space:
mode:
authorMartin Willi <martin@strongswan.org>2006-06-07 13:26:23 +0000
committerMartin Willi <martin@strongswan.org>2006-06-07 13:26:23 +0000
commit8d77eddec2bddbbf44eeec1b95c44a69426c87a6 (patch)
treeb6cc5552d9f19357d9b789ee18d858236089da82 /src/charon/sa/child_sa.c
parenta401efd09157382ba95a398e71995fd67a5fd337 (diff)
downloadstrongswan-8d77eddec2bddbbf44eeec1b95c44a69426c87a6.tar.bz2
strongswan-8d77eddec2bddbbf44eeec1b95c44a69426c87a6.tar.xz
further work for rekeying:
get liftimes from policy added new state initiation of rekeying done proposal redone: removed support for AH+ESP proposals
Diffstat (limited to 'src/charon/sa/child_sa.c')
-rw-r--r--src/charon/sa/child_sa.c443
1 files changed, 193 insertions, 250 deletions
diff --git a/src/charon/sa/child_sa.c b/src/charon/sa/child_sa.c
index b79d07028..2321e4696 100644
--- a/src/charon/sa/child_sa.c
+++ b/src/charon/sa/child_sa.c
@@ -36,25 +36,12 @@ typedef struct sa_policy_t sa_policy_t;
*/
struct sa_policy_t {
- /**
- * Network on local side
- */
- host_t *my_net;
-
- /**
- * Network on remote side
- */
- host_t *other_net;
-
- /**
- * Number of bits for local network (subnet size)
- */
- u_int8_t my_net_mask;
-
- /**
- * Number of bits for remote network (subnet size)
- */
- u_int8_t other_net_mask;
+ struct {
+ /** subnet address behind peer peer */
+ host_t *net;
+ /** netmask used for net */
+ u_int8_t net_mask;
+ } me, other;
/**
* Protocol for this policy, such as TCP/UDP/ICMP...
@@ -73,45 +60,37 @@ struct private_child_sa_t {
*/
child_sa_t public;
- /**
- * IP of this peer
- */
- host_t *me;
+ struct {
+ /** address of peer */
+ host_t *addr;
+ /** actual used SPI, 0 if unused */
+ u_int32_t spi;
+ } me, other;
/**
- * IP of other peer
+ * Protocol used to protect this SA, ESP|AH
*/
- host_t *other;
+ protocol_id_t protocol;
/**
- * Local security parameter index for AH protocol, 0 if not used
+ * List containing sa_policy_t objects
*/
- u_int32_t my_ah_spi;
-
- /**
- * Local security parameter index for ESP protocol, 0 if not used
- */
- u_int32_t my_esp_spi;
-
- /**
- * Remote security parameter index for AH protocol, 0 if not used
- */
- u_int32_t other_ah_spi;
+ linked_list_t *policies;
/**
- * Remote security parameter index for ESP protocol, 0 if not used
+ * reqid used for this child_sa
*/
- u_int32_t other_esp_spi;
+ u_int32_t reqid;
/**
- * List containing policy_id_t objects
+ * Lifetime before rekeying
*/
- linked_list_t *policies;
+ u_int32_t soft_lifetime;
/**
- * reqid used for this child_sa
+ * Lifetime before delete
*/
- u_int32_t reqid;
+ u_int32_t hard_lifetime;
/**
* CHILD_SAs own logger
@@ -126,13 +105,33 @@ static u_int32_t get_reqid(private_child_sa_t *this)
{
return this->reqid;
}
+
+/**
+ * Implements child_sa_t.get_spi
+ */
+u_int32_t get_spi(private_child_sa_t *this, bool inbound)
+{
+ if (inbound)
+ {
+ return this->me.spi;
+ }
+ return this->other.spi;
+}
+
+/**
+ * Implements child_sa_t.get_protocol
+ */
+protocol_id_t get_protocol(private_child_sa_t *this)
+{
+ return this->protocol;
+}
/**
* Implements child_sa_t.alloc
*/
static status_t alloc(private_child_sa_t *this, linked_list_t *proposals)
{
- protocol_id_t protocols[2];
+ protocol_id_t protocol;
iterator_t *iterator;
proposal_t *proposal;
status_t status;
@@ -143,50 +142,21 @@ static status_t alloc(private_child_sa_t *this, linked_list_t *proposals)
while(iterator->has_next(iterator))
{
iterator->current(iterator, (void**)&proposal);
- proposal->get_protocols(proposal, protocols);
-
- /* check all protocols */
- for (i = 0; i<2; i++)
+ protocol = proposal->get_protocol(proposal);
+
+ status = charon->kernel_interface->get_spi(
+ charon->kernel_interface,
+ this->me.addr, this->other.addr,
+ protocol, FALSE,
+ &(this->me.spi));
+
+ if (status != SUCCESS)
{
- switch (protocols[i])
- {
- case PROTO_AH:
- /* do we already have an spi for AH?*/
- if (this->my_ah_spi == 0)
- {
- /* nope, get one */
- status = charon->kernel_interface->get_spi(
- charon->kernel_interface,
- this->me, this->other,
- PROTO_AH, FALSE,
- &(this->my_ah_spi));
- }
- /* update proposal */
- proposal->set_spi(proposal, PROTO_AH, (u_int64_t)this->my_ah_spi);
- break;
- case PROTO_ESP:
- /* do we already have an spi for ESP?*/
- if (this->my_esp_spi == 0)
- {
- /* nope, get one */
- status = charon->kernel_interface->get_spi(
- charon->kernel_interface,
- this->me, this->other,
- PROTO_ESP, FALSE,
- &(this->my_esp_spi));
- }
- /* update proposal */
- proposal->set_spi(proposal, PROTO_ESP, (u_int64_t)this->my_esp_spi);
- break;
- default:
- break;
- }
- if (status != SUCCESS)
- {
- iterator->destroy(iterator);
- return FAILED;
- }
+ iterator->destroy(iterator);
+ return FAILED;
}
+ /* update proposal */
+ proposal->set_spi(proposal, (u_int64_t)this->me.spi);
}
iterator->destroy(iterator);
return SUCCESS;
@@ -194,7 +164,6 @@ static status_t alloc(private_child_sa_t *this, linked_list_t *proposals)
static status_t install(private_child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus, bool mine)
{
- protocol_id_t protocols[2];
u_int32_t spi;
encryption_algorithm_t enc_algo;
integrity_algorithm_t int_algo;
@@ -206,128 +175,103 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, prf_plus
host_t *src;
host_t *dst;
status_t status;
- u_int i;
/* we must assign the roles to correctly set up the SAs */
if (mine)
{
- src = this->me;
- dst = this->other;
+ src = this->me.addr;
+ dst = this->other.addr;
}
else
{
- dst = this->me;
- src = this->other;
+ dst = this->me.addr;
+ src = this->other.addr;
}
- proposal->get_protocols(proposal, protocols);
- /* derive keys in order as protocols appear */
- for (i = 0; i<2; i++)
+ this->protocol = proposal->get_protocol(proposal);
+
+ /* 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] != PROTO_NONE)
- {
-
- /* 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] == PROTO_AH)
- {
- spi = this->my_ah_spi;
- }
- else
- {
- spi = this->my_esp_spi;
- }
- }
- else /* use proposals spi */
- {
- spi = proposal->get_spi(proposal, protocols[i]);
- if (protocols[i] == PROTO_AH)
- {
- this->other_ah_spi = spi;
- }
- else
- {
- this->other_esp_spi = spi;
- }
- }
-
- /* derive encryption key first */
- if (proposal->get_algorithm(proposal, protocols[i], ENCRYPTION_ALGORITHM, &algo))
- {
- 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, enc_algo));
-
- /* 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;
- }
-
- /* derive integrity key */
- if (proposal->get_algorithm(proposal, protocols[i], INTEGRITY_ALGORITHM, &algo))
- {
- 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));
-
- 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],
- this->reqid,
- 5, 30,
- enc_algo, enc_key,
- int_algo, int_key, mine);
- /* clean up for next round */
- if (enc_algo != ENCR_UNDEFINED)
- {
- chunk_free(&enc_key);
- }
- if (int_algo != AUTH_UNDEFINED)
- {
- chunk_free(&int_key);
- }
-
- if (status != SUCCESS)
- {
- return FAILED;
- }
- }
+ spi = this->me.spi;
}
- return SUCCESS;
+ else
+ {
+ spi = proposal->get_spi(proposal);
+ this->other.spi = spi;
+ }
+
+ /* derive encryption key first */
+ if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &algo))
+ {
+ enc_algo = algo->algorithm;
+ this->logger->log(this->logger, CONTROL|LEVEL1, "%s for %s: using %s %s, ",
+ mapping_find(protocol_id_m, this->protocol),
+ mine ? "me" : "other",
+ mapping_find(transform_type_m, ENCRYPTION_ALGORITHM),
+ mapping_find(encryption_algorithm_m, enc_algo));
+
+ /* 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;
+ }
+
+ /* derive integrity key */
+ if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &algo))
+ {
+ int_algo = algo->algorithm;
+ this->logger->log(this->logger, CONTROL|LEVEL1, "%s for %s: using %s %s,",
+ mapping_find(protocol_id_m, this->protocol),
+ mine ? "me" : "other",
+ mapping_find(transform_type_m, INTEGRITY_ALGORITHM),
+ mapping_find(integrity_algorithm_m, algo->algorithm));
+
+ 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, this->protocol),
+ src->get_address(src), dst->get_address(dst));
+ status = charon->kernel_interface->add_sa(charon->kernel_interface,
+ src, dst,
+ spi, this->protocol,
+ this->reqid,
+ mine ? 0 : this->soft_lifetime,
+ this->hard_lifetime,
+ enc_algo, enc_key,
+ int_algo, int_key, mine);
+ /* clean up */
+ if (enc_algo != ENCR_UNDEFINED)
+ {
+ chunk_free(&enc_key);
+ }
+ if (int_algo != AUTH_UNDEFINED)
+ {
+ chunk_free(&int_key);
+ }
+ return status;
}
static status_t add(private_child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus)
@@ -412,8 +356,8 @@ static status_t add_policies(private_child_sa_t *this, linked_list_t *my_ts_list
from_port = my_ts->get_from_port(my_ts);
to_port = my_ts->get_to_port(my_ts);
from_port = (from_port != to_port) ? 0 : from_port;
- policy->my_net = host_create_from_chunk(family, from_addr, from_port);
- policy->my_net_mask = my_ts->get_netmask(my_ts);
+ policy->me.net = host_create_from_chunk(family, from_addr, from_port);
+ policy->me.net_mask = my_ts->get_netmask(my_ts);
chunk_free(&from_addr);
/* calculate net and ports for remote side */
@@ -422,41 +366,44 @@ static status_t add_policies(private_child_sa_t *this, linked_list_t *my_ts_list
from_port = other_ts->get_from_port(other_ts);
to_port = other_ts->get_to_port(other_ts);
from_port = (from_port != to_port) ? 0 : from_port;
- policy->other_net = host_create_from_chunk(family, from_addr, from_port);
- policy->other_net_mask = other_ts->get_netmask(other_ts);
+ policy->other.net = host_create_from_chunk(family, from_addr, from_port);
+ policy->other.net_mask = other_ts->get_netmask(other_ts);
chunk_free(&from_addr);
/* install 3 policies: out, in and forward */
status = charon->kernel_interface->add_policy(charon->kernel_interface,
- this->me, this->other,
- policy->my_net, policy->other_net,
- policy->my_net_mask, policy->other_net_mask,
+ 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,
- this->my_ah_spi, this->my_esp_spi,
+ this->protocol == PROTO_AH,
+ this->protocol == PROTO_ESP,
this->reqid);
status |= charon->kernel_interface->add_policy(charon->kernel_interface,
- this->other, this->me,
- policy->other_net, policy->my_net,
- policy->other_net_mask, policy->my_net_mask,
+ 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,
- this->my_ah_spi, this->my_esp_spi,
+ this->protocol == PROTO_AH,
+ this->protocol == PROTO_ESP,
this->reqid);
status |= charon->kernel_interface->add_policy(charon->kernel_interface,
- this->other, this->me,
- policy->other_net, policy->my_net,
- policy->other_net_mask, policy->my_net_mask,
+ 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,
- this->my_ah_spi, this->my_esp_spi,
+ this->protocol == PROTO_AH,
+ this->protocol == PROTO_ESP,
this->reqid);
if (status != SUCCESS)
{
my_iter->destroy(my_iter);
other_iter->destroy(other_iter);
- policy->my_net->destroy(policy->my_net);
- policy->other_net->destroy(policy->other_net);
+ policy->me.net->destroy(policy->me.net);
+ policy->other.net->destroy(policy->other.net);
free(policy);
return status;
}
@@ -465,7 +412,6 @@ static status_t add_policies(private_child_sa_t *this, linked_list_t *my_ts_list
this->policies->insert_last(this->policies, policy);
}
}
-
my_iter->destroy(my_iter);
other_iter->destroy(other_iter);
return SUCCESS;
@@ -486,10 +432,11 @@ static void log_status(private_child_sa_t *this, logger_t *logger, char* name)
{
logger = this->logger;
}
- logger->log(logger, CONTROL|LEVEL1, " \"%s\": protected with ESP (0x%x/0x%x), AH (0x%x,0x%x):",
+ logger->log(logger, CONTROL|LEVEL1, " \"%s\": protected with %s (0x%x/0x%x), reqid %d:",
name,
- htonl(this->my_esp_spi), htonl(this->other_esp_spi),
- htonl(this->my_ah_spi), htonl(this->other_ah_spi));
+ this->protocol == PROTO_ESP ? "ESP" : "AH",
+ htonl(this->me.spi), htonl(this->other.spi),
+ this->reqid);
iterator = this->policies->create_iterator(this->policies, TRUE);
while (iterator->has_next(iterator))
{
@@ -508,9 +455,9 @@ static void log_status(private_child_sa_t *this, logger_t *logger, char* name)
}
logger->log(logger, CONTROL, " \"%s\": %s/%d==%s==%s/%d",
name,
- policy->my_net->get_address(policy->my_net), policy->my_net_mask,
+ policy->me.net->get_address(policy->me.net), policy->me.net_mask,
proto_name,
- policy->other_net->get_address(policy->other_net), policy->other_net_mask);
+ policy->other.net->get_address(policy->other.net), policy->other.net_mask);
}
iterator->destroy(iterator);
}
@@ -525,43 +472,36 @@ static void destroy(private_child_sa_t *this)
while (this->policies->remove_last(this->policies, (void**)&policy) == SUCCESS)
{
charon->kernel_interface->del_policy(charon->kernel_interface,
- this->me, this->other,
- policy->my_net, policy->other_net,
- policy->my_net_mask, policy->other_net_mask,
+ 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, this->me,
- policy->other_net, policy->my_net,
- policy->other_net_mask, policy->my_net_mask,
+ 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, this->me,
- policy->other_net, policy->my_net,
- policy->other_net_mask, policy->my_net_mask,
+ 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->my_net->destroy(policy->my_net);
- policy->other_net->destroy(policy->other_net);
+ 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->my_ah_spi)
- {
- charon->kernel_interface->del_sa(charon->kernel_interface,
- this->other, this->my_ah_spi, PROTO_AH);
- charon->kernel_interface->del_sa(charon->kernel_interface,
- this->me, this->other_ah_spi, PROTO_AH);
- }
- if (this->my_esp_spi)
+ if (this->protocol != PROTO_NONE)
{
charon->kernel_interface->del_sa(charon->kernel_interface,
- this->other, this->my_esp_spi, PROTO_ESP);
+ this->other.addr, this->me.spi, this->protocol);
charon->kernel_interface->del_sa(charon->kernel_interface,
- this->me, this->other_esp_spi, PROTO_ESP);
+ this->me.addr, this->other.spi, this->protocol);
}
free(this);
}
@@ -569,13 +509,15 @@ static void destroy(private_child_sa_t *this)
/*
* Described in header.
*/
-child_sa_t * child_sa_create(host_t *me, host_t* other)
+child_sa_t * child_sa_create(host_t *me, host_t* other, u_int32_t soft_lifetime, u_int32_t hard_lifetime)
{
static u_int32_t reqid = 2000000000;
private_child_sa_t *this = malloc_thing(private_child_sa_t);
/* public functions */
this->public.get_reqid = (u_int32_t(*)(child_sa_t*))get_reqid;
+ this->public.get_spi = (u_int32_t(*)(child_sa_t*, bool))get_spi;
+ this->public.get_protocol = (protocol_id_t(*)(child_sa_t*))get_protocol;
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;
@@ -585,14 +527,15 @@ child_sa_t * child_sa_create(host_t *me, host_t* other)
/* private data */
this->logger = logger_manager->get_logger(logger_manager, CHILD_SA);
- this->me = me;
- this->other = other;
- this->my_ah_spi = 0;
- this->my_esp_spi = 0;
- this->other_ah_spi = 0;
- this->other_esp_spi = 0;
+ this->me.addr = me;
+ this->other.addr = other;
+ this->me.spi = 0;
+ this->other.spi = 0;
+ this->soft_lifetime = soft_lifetime;
+ this->hard_lifetime = hard_lifetime;
this->reqid = ++reqid;
this->policies = linked_list_create();
+ this->protocol = PROTO_NONE;
return (&this->public);
}