summaryrefslogtreecommitdiff
path: root/src/charon/sa/tasks
diff options
context:
space:
mode:
Diffstat (limited to 'src/charon/sa/tasks')
-rw-r--r--src/charon/sa/tasks/child_create.c259
-rw-r--r--src/charon/sa/tasks/child_create.h6
-rw-r--r--src/charon/sa/tasks/child_delete.c22
-rw-r--r--src/charon/sa/tasks/child_rekey.c19
-rw-r--r--src/charon/sa/tasks/ike_auth.c66
-rw-r--r--src/charon/sa/tasks/ike_cert.c50
-rw-r--r--src/charon/sa/tasks/ike_config.c45
-rw-r--r--src/charon/sa/tasks/ike_config.h5
-rw-r--r--src/charon/sa/tasks/ike_delete.c3
-rw-r--r--src/charon/sa/tasks/ike_init.c137
-rw-r--r--src/charon/sa/tasks/ike_rekey.c77
11 files changed, 425 insertions, 264 deletions
diff --git a/src/charon/sa/tasks/child_create.c b/src/charon/sa/tasks/child_create.c
index 781d679f2..f70730b05 100644
--- a/src/charon/sa/tasks/child_create.c
+++ b/src/charon/sa/tasks/child_create.c
@@ -26,6 +26,7 @@
#include <daemon.h>
#include <crypto/diffie_hellman.h>
#include <encoding/payloads/sa_payload.h>
+#include <encoding/payloads/ke_payload.h>
#include <encoding/payloads/ts_payload.h>
#include <encoding/payloads/nonce_payload.h>
#include <encoding/payloads/notify_payload.h>
@@ -64,9 +65,9 @@ struct private_child_create_t {
chunk_t other_nonce;
/**
- * policy to create the CHILD_SA from
+ * config to create the CHILD_SA from
*/
- policy_t *policy;
+ child_cfg_t *config;
/**
* list of proposal candidates
@@ -89,6 +90,16 @@ struct private_child_create_t {
linked_list_t *tsr;
/**
+ * optional diffie hellman exchange
+ */
+ diffie_hellman_t *dh;
+
+ /**
+ * group used for DH exchange
+ */
+ diffie_hellman_group_t dh_group;
+
+ /**
* mode the new CHILD_SA uses (transport/tunnel/beet)
*/
mode_t mode;
@@ -162,21 +173,29 @@ static bool ts_list_is_host(linked_list_t *list, host_t *host)
}
/**
- * Install a CHILD_SA for usage
+ * Install a CHILD_SA for usage, return value:
+ * - FAILED: no acceptable proposal
+ * - INVALID_ARG: diffie hellman group inacceptable
+ * - NOT_FOUND: TS inacceptable
*/
-static status_t select_and_install(private_child_create_t *this)
+static status_t select_and_install(private_child_create_t *this, bool no_dh)
{
prf_plus_t *prf_plus;
status_t status;
- chunk_t nonce_i, nonce_r, seed;
+ chunk_t nonce_i, nonce_r, secret, seed;
linked_list_t *my_ts, *other_ts;
host_t *me, *other, *other_vip, *my_vip;
- if (this->proposals == NULL || this->tsi == NULL || this->tsr == NULL)
+ if (this->proposals == NULL)
{
- SIG(CHILD_UP_FAILED, "SA/TS payloads missing in message");
+ SIG(CHILD_UP_FAILED, "SA payload missing in message");
return FAILED;
}
+ if (this->tsi == NULL || this->tsr == NULL)
+ {
+ SIG(CHILD_UP_FAILED, "TS payloads missing in message");
+ return NOT_FOUND;
+ }
if (this->initiator)
{
@@ -198,36 +217,61 @@ static status_t select_and_install(private_child_create_t *this)
my_vip = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
other_vip = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE);
- this->proposal = this->policy->select_proposal(this->policy, this->proposals);
-
+ this->proposal = this->config->select_proposal(this->config, this->proposals,
+ no_dh);
if (this->proposal == NULL)
{
SIG(CHILD_UP_FAILED, "no acceptable proposal found");
return FAILED;
}
- if (this->initiator && my_vip)
- { /* if we have a virtual IP, shorten our TS to the minimum */
- my_ts = this->policy->select_my_traffic_selectors(this->policy, my_ts,
- my_vip);
+ if (!this->proposal->has_dh_group(this->proposal, this->dh_group))
+ {
+ algorithm_t *algo;
+ if (this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP,
+ &algo))
+ {
+ u_int16_t group = algo->algorithm;
+ SIG(CHILD_UP_FAILED, "DH group %N inacceptable, requesting %N",
+ diffie_hellman_group_names, this->dh_group,
+ diffie_hellman_group_names, group);
+ this->dh_group = group;
+ return INVALID_ARG;
+ }
+ else
+ {
+ SIG(CHILD_UP_FAILED, "no acceptable proposal found");
+ return FAILED;
+ }
+ }
+
+ if (my_vip == NULL)
+ {
+ my_vip = me;
+ }
+ else if (this->initiator)
+ {
/* to setup firewall rules correctly, CHILD_SA needs the virtual IP */
this->child_sa->set_virtual_ip(this->child_sa, my_vip);
}
- else
- { /* shorten in the host2host case only */
- my_ts = this->policy->select_my_traffic_selectors(this->policy,
- my_ts, me);
- }
- if (other_vip)
- { /* if other has a virtual IP, shorten it's traffic selectors to it */
- other_ts = this->policy->select_other_traffic_selectors(this->policy,
- other_ts, other_vip);
+ if (other_vip == NULL)
+ {
+ other_vip = other;
}
- else
- { /* use his host for the host2host case */
- other_ts = this->policy->select_other_traffic_selectors(this->policy,
- other_ts, other);
+
+ my_ts = this->config->get_traffic_selectors(this->config, TRUE, my_ts,
+ my_vip);
+ other_ts = this->config->get_traffic_selectors(this->config, FALSE, other_ts,
+ other_vip);
+
+ if (my_ts->get_count(my_ts) == 0 || other_ts->get_count(other_ts) == 0)
+ {
+ my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
+ other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy));
+ SIG(CHILD_UP_FAILED, "no acceptable traffic selectors found");
+ return NOT_FOUND;
}
+
this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy));
this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
if (this->initiator)
@@ -241,13 +285,6 @@ static status_t select_and_install(private_child_create_t *this)
this->tsi = other_ts;
}
- if (this->tsi->get_count(this->tsi) == 0 ||
- this->tsr->get_count(this->tsr) == 0)
- {
- SIG(CHILD_UP_FAILED, "no acceptable traffic selectors found");
- return FAILED;
- }
-
if (!this->initiator)
{
/* check if requested mode is acceptable, downgrade if required */
@@ -279,7 +316,20 @@ static status_t select_and_install(private_child_create_t *this)
}
}
- seed = chunk_cata("cc", nonce_i, nonce_r);
+ if (this->dh)
+ {
+ if (this->dh->get_shared_secret(this->dh, &secret) != SUCCESS)
+ {
+ SIG(CHILD_UP_FAILED, "DH exchange incomplete");
+ return FAILED;
+ }
+ DBG3(DBG_IKE, "DH secret %B", &secret);
+ seed = chunk_cata("mcc", secret, nonce_i, nonce_r);
+ }
+ else
+ {
+ seed = chunk_cata("cc", nonce_i, nonce_r);
+ }
prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed);
if (this->initiator)
@@ -297,7 +347,7 @@ static status_t select_and_install(private_child_create_t *this)
if (status != SUCCESS)
{
SIG(CHILD_UP_FAILED, "unable to install IPsec SA (SAD) in kernel");
- return status;
+ return FAILED;
}
status = this->child_sa->add_policies(this->child_sa, my_ts, other_ts,
@@ -306,7 +356,7 @@ static status_t select_and_install(private_child_create_t *this)
if (status != SUCCESS)
{
SIG(CHILD_UP_FAILED, "unable to install IPsec policies (SPD) in kernel");
- return status;
+ return NOT_FOUND;
}
/* add to IKE_SA, and remove from task */
this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
@@ -321,8 +371,9 @@ static status_t select_and_install(private_child_create_t *this)
static void build_payloads(private_child_create_t *this, message_t *message)
{
sa_payload_t *sa_payload;
- ts_payload_t *ts_payload;
nonce_payload_t *nonce_payload;
+ ke_payload_t *ke_payload;
+ ts_payload_t *ts_payload;
/* add SA payload */
if (this->initiator)
@@ -343,6 +394,13 @@ static void build_payloads(private_child_create_t *this, message_t *message)
message->add_payload(message, (payload_t*)nonce_payload);
}
+ /* diffie hellman exchange, if PFS enabled */
+ if (this->dh)
+ {
+ ke_payload = ke_payload_create_from_diffie_hellman(this->dh);
+ message->add_payload(message, (payload_t*)ke_payload);
+ }
+
/* add TSi/TSr payloads */
ts_payload = ts_payload_create_from_traffic_selectors(TRUE, this->tsi);
message->add_payload(message, (payload_t*)ts_payload);
@@ -371,6 +429,7 @@ static void process_payloads(private_child_create_t *this, message_t *message)
iterator_t *iterator;
payload_t *payload;
sa_payload_t *sa_payload;
+ ke_payload_t *ke_payload;
ts_payload_t *ts_payload;
notify_payload_t *notify_payload;
@@ -386,6 +445,19 @@ static void process_payloads(private_child_create_t *this, message_t *message)
sa_payload = (sa_payload_t*)payload;
this->proposals = sa_payload->get_proposals(sa_payload);
break;
+ case KEY_EXCHANGE:
+ ke_payload = (ke_payload_t*)payload;
+ if (!this->initiator)
+ {
+ this->dh_group = ke_payload->get_dh_group_number(ke_payload);
+ this->dh = diffie_hellman_create(this->dh_group);
+ }
+ if (this->dh)
+ {
+ this->dh->set_other_public_value(this->dh,
+ ke_payload->get_key_exchange_data(ke_payload));
+ }
+ break;
case TRAFFIC_SELECTOR_INITIATOR:
ts_payload = (ts_payload_t*)payload;
this->tsi = ts_payload->get_traffic_selectors(ts_payload);
@@ -421,6 +493,7 @@ static void process_payloads(private_child_create_t *this, message_t *message)
static status_t build_i(private_child_create_t *this, message_t *message)
{
host_t *me, *other, *vip;
+ peer_cfg_t *peer_cfg;
switch (message->get_exchange_type(message))
{
@@ -432,6 +505,10 @@ static status_t build_i(private_child_create_t *this, message_t *message)
message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty);
return SUCCESS;
}
+ if (this->dh_group == MODP_NONE)
+ {
+ this->dh_group = this->config->get_dh_group(this->config);
+ }
break;
case IKE_AUTH:
if (!message->get_payload(message, ID_INITIATOR))
@@ -448,25 +525,30 @@ static status_t build_i(private_child_create_t *this, message_t *message)
me = this->ike_sa->get_my_host(this->ike_sa);
other = this->ike_sa->get_other_host(this->ike_sa);
- vip = this->policy->get_virtual_ip(this->policy, NULL);
+ peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
+ vip = peer_cfg->get_my_virtual_ip(peer_cfg);
if (vip)
{ /* propose a 0.0.0.0/0 subnet when we use virtual ip */
- this->tsi = this->policy->get_my_traffic_selectors(this->policy, NULL);
+ this->tsi = this->config->get_traffic_selectors(this->config, TRUE,
+ NULL, NULL);
vip->destroy(vip);
}
else
{ /* but shorten a 0.0.0.0/0 subnet to the actual address if host2host */
- this->tsi = this->policy->get_my_traffic_selectors(this->policy, me);
+ this->tsi = this->config->get_traffic_selectors(this->config, TRUE,
+ NULL, me);
}
- this->tsr = this->policy->get_other_traffic_selectors(this->policy, other);
- this->proposals = this->policy->get_proposals(this->policy);
- this->mode = this->policy->get_mode(this->policy);
+ this->tsr = this->config->get_traffic_selectors(this->config, FALSE,
+ NULL, other);
+ this->proposals = this->config->get_proposals(this->config,
+ this->dh_group == MODP_NONE);
+ this->mode = this->config->get_mode(this->config);
this->child_sa = child_sa_create(me, other,
this->ike_sa->get_my_id(this->ike_sa),
this->ike_sa->get_other_id(this->ike_sa),
- this->policy, this->reqid,
+ this->config, this->reqid,
this->ike_sa->is_natt_enabled(this->ike_sa));
if (this->child_sa->alloc(this->child_sa, this->proposals) != SUCCESS)
@@ -475,6 +557,11 @@ static status_t build_i(private_child_create_t *this, message_t *message)
return FAILED;
}
+ if (this->dh_group != MODP_NONE)
+ {
+ this->dh = diffie_hellman_create(this->dh_group);
+ }
+
build_payloads(this, message);
this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
@@ -492,6 +579,8 @@ static status_t build_i(private_child_create_t *this, message_t *message)
*/
static status_t process_r(private_child_create_t *this, message_t *message)
{
+ peer_cfg_t *peer_cfg;
+
switch (message->get_exchange_type(message))
{
case IKE_SA_INIT:
@@ -517,18 +606,13 @@ static status_t process_r(private_child_create_t *this, message_t *message)
return NEED_MORE;
}
- this->policy = charon->policies->get_policy(charon->policies,
- this->ike_sa->get_my_id(this->ike_sa),
- this->ike_sa->get_other_id(this->ike_sa),
- this->tsr, this->tsi,
- this->ike_sa->get_my_host(this->ike_sa),
- this->ike_sa->get_other_host(this->ike_sa));
-
- if (this->policy && this->ike_sa->get_policy(this->ike_sa) == NULL)
+ peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
+ if (peer_cfg)
{
- this->ike_sa->set_policy(this->ike_sa, this->policy);
+ this->config = peer_cfg->select_child_cfg(peer_cfg, this->tsr, this->tsi,
+ this->ike_sa->get_my_host(this->ike_sa),
+ this->ike_sa->get_other_host(this->ike_sa));
}
-
return NEED_MORE;
}
@@ -537,6 +621,8 @@ static status_t process_r(private_child_create_t *this, message_t *message)
*/
static status_t build_r(private_child_create_t *this, message_t *message)
{
+ bool no_dh = TRUE;
+
switch (message->get_exchange_type(message))
{
case IKE_SA_INIT:
@@ -547,6 +633,7 @@ static status_t build_r(private_child_create_t *this, message_t *message)
message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty);
return SUCCESS;
}
+ no_dh = FALSE;
break;
case IKE_AUTH:
if (message->get_payload(message, EXTENSIBLE_AUTHENTICATION))
@@ -565,10 +652,11 @@ static status_t build_r(private_child_create_t *this, message_t *message)
return SUCCESS;
}
- if (this->policy == NULL)
+ if (this->config == NULL)
{
- SIG(CHILD_UP_FAILED, "no acceptable policy found");
- message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty);
+ SIG(CHILD_UP_FAILED, "traffic selectors %#R=== %#R inacceptable",
+ this->tsr, this->tsi);
+ message->add_notify(message, FALSE, TS_UNACCEPTABLE, chunk_empty);
return SUCCESS;
}
@@ -576,13 +664,27 @@ static status_t build_r(private_child_create_t *this, message_t *message)
this->ike_sa->get_other_host(this->ike_sa),
this->ike_sa->get_my_id(this->ike_sa),
this->ike_sa->get_other_id(this->ike_sa),
- this->policy, this->reqid,
+ this->config, this->reqid,
this->ike_sa->is_natt_enabled(this->ike_sa));
- if (select_and_install(this) != SUCCESS)
+ switch (select_and_install(this, no_dh))
{
- message->add_notify(message, FALSE, TS_UNACCEPTABLE, chunk_empty);
- return SUCCESS;
+ case SUCCESS:
+ break;
+ case NOT_FOUND:
+ message->add_notify(message, FALSE, TS_UNACCEPTABLE, chunk_empty);
+ return SUCCESS;
+ case INVALID_ARG:
+ {
+ u_int16_t group = htons(this->dh_group);
+ message->add_notify(message, FALSE, INVALID_KE_PAYLOAD,
+ chunk_from_thing(group));
+ return SUCCESS;
+ }
+ case FAILED:
+ default:
+ message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty);
+ return SUCCESS;
}
build_payloads(this, message);
@@ -599,6 +701,7 @@ static status_t process_i(private_child_create_t *this, message_t *message)
{
iterator_t *iterator;
payload_t *payload;
+ bool no_dh = TRUE;
switch (message->get_exchange_type(message))
{
@@ -606,6 +709,7 @@ static status_t process_i(private_child_create_t *this, message_t *message)
return get_nonce(message, &this->other_nonce);
case CREATE_CHILD_SA:
get_nonce(message, &this->other_nonce);
+ no_dh = FALSE;
break;
case IKE_AUTH:
if (message->get_payload(message, EXTENSIBLE_AUTHENTICATION))
@@ -643,6 +747,22 @@ static status_t process_i(private_child_create_t *this, message_t *message)
/* an error in CHILD_SA creation is not critical */
return SUCCESS;
}
+ case INVALID_KE_PAYLOAD:
+ {
+ chunk_t data;
+ diffie_hellman_group_t bad_group;
+
+ bad_group = this->dh_group;
+ data = notify->get_notification_data(notify);
+ this->dh_group = ntohs(*((u_int16_t*)data.ptr));
+ DBG1(DBG_IKE, "peer didn't accept DH group %N, "
+ "it requested %N", diffie_hellman_group_names,
+ bad_group, diffie_hellman_group_names, this->dh_group);
+
+ this->public.task.migrate(&this->public.task, this->ike_sa);
+ iterator->destroy(iterator);
+ return NEED_MORE;
+ }
default:
break;
}
@@ -652,7 +772,7 @@ static status_t process_i(private_child_create_t *this, message_t *message)
process_payloads(this, message);
- if (select_and_install(this) == SUCCESS)
+ if (select_and_install(this, no_dh) == SUCCESS)
{
SIG(CHILD_UP_SUCCESS, "established CHILD_SA successfully");
}
@@ -716,6 +836,7 @@ static void migrate(private_child_create_t *this, ike_sa_t *ike_sa)
}
DESTROY_IF(this->child_sa);
DESTROY_IF(this->proposal);
+ DESTROY_IF(this->dh);
if (this->proposals)
{
this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
@@ -725,6 +846,7 @@ static void migrate(private_child_create_t *this, ike_sa_t *ike_sa)
this->proposals = NULL;
this->tsi = NULL;
this->tsr = NULL;
+ this->dh = NULL;
this->child_sa = NULL;
this->mode = MODE_TUNNEL;
this->reqid = 0;
@@ -751,19 +873,20 @@ static void destroy(private_child_create_t *this)
DESTROY_IF(this->child_sa);
}
DESTROY_IF(this->proposal);
+ DESTROY_IF(this->dh);
if (this->proposals)
{
this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
}
- DESTROY_IF(this->policy);
+ DESTROY_IF(this->config);
free(this);
}
/*
* Described in header.
*/
-child_create_t *child_create_create(ike_sa_t *ike_sa, policy_t *policy)
+child_create_t *child_create_create(ike_sa_t *ike_sa, child_cfg_t *config)
{
private_child_create_t *this = malloc_thing(private_child_create_t);
@@ -773,12 +896,12 @@ child_create_t *child_create_create(ike_sa_t *ike_sa, policy_t *policy)
this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
this->public.task.destroy = (void(*)(task_t*))destroy;
- if (policy)
+ if (config)
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
this->initiator = TRUE;
- policy->get_ref(policy);
+ config->get_ref(config);
}
else
{
@@ -788,13 +911,15 @@ child_create_t *child_create_create(ike_sa_t *ike_sa, policy_t *policy)
}
this->ike_sa = ike_sa;
- this->policy = policy;
+ this->config = config;
this->my_nonce = chunk_empty;
this->other_nonce = chunk_empty;
this->proposals = NULL;
this->proposal = NULL;
this->tsi = NULL;
this->tsr = NULL;
+ this->dh = NULL;
+ this->dh_group = MODP_NONE;
this->child_sa = NULL;
this->mode = MODE_TUNNEL;
this->reqid = 0;
diff --git a/src/charon/sa/tasks/child_create.h b/src/charon/sa/tasks/child_create.h
index 200d37457..9f4815215 100644
--- a/src/charon/sa/tasks/child_create.h
+++ b/src/charon/sa/tasks/child_create.h
@@ -28,7 +28,7 @@ typedef struct child_create_t child_create_t;
#include <library.h>
#include <sa/ike_sa.h>
#include <sa/tasks/task.h>
-#include <config/policies/policy.h>
+#include <config/child_cfg.h>
/**
* @brief Task of type CHILD_CREATE, established a new CHILD_SA.
@@ -80,9 +80,9 @@ struct child_create_t {
* @brief Create a new child_create task.
*
* @param ike_sa IKE_SA this task works for
- * @param policy policy if task initiator, NULL if responder
+ * @param config child_cfg if task initiator, NULL if responder
* @return child_create task to handle by the task_manager
*/
-child_create_t *child_create_create(ike_sa_t *ike_sa, policy_t *policy);
+child_create_t *child_create_create(ike_sa_t *ike_sa, child_cfg_t *config);
#endif /* CHILD_CREATE_H_ */
diff --git a/src/charon/sa/tasks/child_delete.c b/src/charon/sa/tasks/child_delete.c
index 23d509de5..d0b34a276 100644
--- a/src/charon/sa/tasks/child_delete.c
+++ b/src/charon/sa/tasks/child_delete.c
@@ -177,10 +177,29 @@ static void destroy_children(private_child_delete_t *this)
}
/**
+ * send closing signals for all CHILD_SAs over the bus
+ */
+static void log_children(private_child_delete_t *this)
+{
+ iterator_t *iterator;
+ child_sa_t *child_sa;
+
+ iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
+ while (iterator->iterate(iterator, (void**)&child_sa))
+ {
+ SIG(CHILD_DOWN_START, "closing CHILD_SA %#R=== %#R",
+ child_sa->get_traffic_selectors(child_sa, TRUE),
+ child_sa->get_traffic_selectors(child_sa, FALSE));
+ }
+ iterator->destroy(iterator);
+}
+
+/**
* Implementation of task_t.build for initiator
*/
static status_t build_i(private_child_delete_t *this, message_t *message)
{
+ log_children(this);
build_payloads(this, message);
return NEED_MORE;
}
@@ -196,6 +215,7 @@ static status_t process_i(private_child_delete_t *this, message_t *message)
process_payloads(this, message);
destroy_children(this);
+ SIG(CHILD_DOWN_SUCCESS, "CHILD_SA closed");
return SUCCESS;
}
@@ -205,6 +225,7 @@ static status_t process_i(private_child_delete_t *this, message_t *message)
static status_t process_r(private_child_delete_t *this, message_t *message)
{
process_payloads(this, message);
+ log_children(this);
return NEED_MORE;
}
@@ -219,6 +240,7 @@ static status_t build_r(private_child_delete_t *this, message_t *message)
build_payloads(this, message);
}
destroy_children(this);
+ SIG(CHILD_DOWN_SUCCESS, "CHILD_SA closed");
return SUCCESS;
}
diff --git a/src/charon/sa/tasks/child_rekey.c b/src/charon/sa/tasks/child_rekey.c
index 745895dbb..4f3c69034 100644
--- a/src/charon/sa/tasks/child_rekey.c
+++ b/src/charon/sa/tasks/child_rekey.c
@@ -27,7 +27,7 @@
#include <encoding/payloads/notify_payload.h>
#include <sa/tasks/child_create.h>
#include <sa/tasks/child_delete.h>
-#include <queues/jobs/rekey_child_sa_job.h>
+#include <processing/jobs/rekey_child_sa_job.h>
typedef struct private_child_rekey_t private_child_rekey_t;
@@ -183,7 +183,12 @@ static status_t process_i(private_child_rekey_t *this, message_t *message)
u_int32_t spi;
child_sa_t *to_delete;
- this->child_create->task.process(&this->child_create->task, message);
+ if (this->child_create->task.process(&this->child_create->task, message) == NEED_MORE)
+ {
+ /* bad DH group while rekeying, try again */
+ this->child_create->task.migrate(&this->child_create->task, this->ike_sa);
+ return NEED_MORE;
+ }
if (message->get_payload(message, SECURITY_ASSOCIATION) == NULL)
{
/* establishing new child failed, reuse old. but not when we
@@ -192,8 +197,8 @@ static status_t process_i(private_child_rekey_t *this, message_t *message)
this->collision->get_type(this->collision) == CHILD_DELETE))
{
job_t *job;
- u_int32_t retry = charon->configuration->get_retry_interval(
- charon->configuration);
+ u_int32_t retry = RETRY_INTERVAL - (random() % RETRY_JITTER);
+
job = (job_t*)rekey_child_sa_job_create(
this->child_sa->get_reqid(this->child_sa),
this->child_sa->get_protocol(this->child_sa),
@@ -315,8 +320,8 @@ static void destroy(private_child_rekey_t *this)
*/
child_rekey_t *child_rekey_create(ike_sa_t *ike_sa, child_sa_t *child_sa)
{
+ child_cfg_t *config;
private_child_rekey_t *this = malloc_thing(private_child_rekey_t);
- policy_t *policy;
this->public.collide = (void (*)(child_rekey_t*,task_t*))collide;
this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
@@ -327,8 +332,8 @@ child_rekey_t *child_rekey_create(ike_sa_t *ike_sa, child_sa_t *child_sa)
this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
this->initiator = TRUE;
- policy = child_sa->get_policy(child_sa);
- this->child_create = child_create_create(ike_sa, policy);
+ config = child_sa->get_config(child_sa);
+ this->child_create = child_create_create(ike_sa, config);
}
else
{
diff --git a/src/charon/sa/tasks/ike_auth.c b/src/charon/sa/tasks/ike_auth.c
index 541e1bb37..d0dd49aee 100644
--- a/src/charon/sa/tasks/ike_auth.c
+++ b/src/charon/sa/tasks/ike_auth.c
@@ -100,18 +100,18 @@ static status_t build_auth(private_ike_auth_t *this, message_t *message)
{
authenticator_t *auth;
auth_payload_t *auth_payload;
- policy_t *policy;
+ peer_cfg_t *config;
auth_method_t method;
status_t status;
/* create own authenticator and add auth payload */
- policy = this->ike_sa->get_policy(this->ike_sa);
- if (!policy)
+ config = this->ike_sa->get_peer_cfg(this->ike_sa);
+ if (!config)
{
- SIG(IKE_UP_FAILED, "unable to authenticate, no policy found");
+ SIG(IKE_UP_FAILED, "unable to authenticate, no peer config found");
return FAILED;
}
- method = policy->get_auth_method(policy);
+ method = config->get_auth_method(config);
auth = authenticator_create(this->ike_sa, method);
if (auth == NULL)
@@ -140,15 +140,15 @@ static status_t build_id(private_ike_auth_t *this, message_t *message)
{
identification_t *me, *other;
id_payload_t *id;
- policy_t *policy;
+ peer_cfg_t *config;
me = this->ike_sa->get_my_id(this->ike_sa);
other = this->ike_sa->get_other_id(this->ike_sa);
- policy = this->ike_sa->get_policy(this->ike_sa);
+ config = this->ike_sa->get_peer_cfg(this->ike_sa);
if (me->contains_wildcards(me))
{
- me = policy->get_my_id(policy);
+ me = config->get_my_id(config);
if (me->contains_wildcards(me))
{
SIG(IKE_UP_FAILED, "negotiation of own ID failed");
@@ -202,7 +202,7 @@ static status_t process_auth(private_ike_auth_t *this, message_t *message)
auth->destroy(auth);
if (status != SUCCESS)
{
- SIG(IKE_UP_FAILED, "authentication of %D using %N failed",
+ SIG(IKE_UP_FAILED, "authentication of '%D' with %N failed",
this->ike_sa->get_other_id(this->ike_sa),
auth_method_names, auth_method);
return FAILED;
@@ -215,7 +215,7 @@ static status_t process_auth(private_ike_auth_t *this, message_t *message)
*/
static status_t process_id(private_ike_auth_t *this, message_t *message)
{
- identification_t *id;
+ identification_t *id, *req;
id_payload_t *idr, *idi;
idi = (id_payload_t*)message->get_payload(message, ID_INITIATOR);
@@ -230,6 +230,13 @@ static status_t process_id(private_ike_auth_t *this, message_t *message)
if (this->initiator)
{
id = idr->get_identification(idr);
+ req = this->ike_sa->get_other_id(this->ike_sa);
+ if (!id->matches(id, req, NULL))
+ {
+ SIG(IKE_UP_FAILED, "peer ID %D unacceptable, %D required", id, req);
+ id->destroy(id);
+ return FAILED;
+ }
this->ike_sa->set_other_id(this->ike_sa, id);
}
else
@@ -346,7 +353,7 @@ static status_t process_auth_eap(private_ike_auth_t *this, message_t *message)
if (!this->peer_authenticated)
{
- SIG(IKE_UP_FAILED, "authentication of %D using %N failed",
+ SIG(IKE_UP_FAILED, "authentication of '%D' with %N failed",
this->ike_sa->get_other_id(this->ike_sa),
auth_method_names, AUTH_EAP);
if (this->initiator)
@@ -444,7 +451,7 @@ static status_t build_eap_r(private_ike_auth_t *this, message_t *message)
this->public.task.process = (status_t(*)(task_t*,message_t*))process_auth_eap;
break;
default:
- SIG(IKE_UP_FAILED, "authentication of %D using %N failed",
+ SIG(IKE_UP_FAILED, "authentication of '%D' with %N failed",
this->ike_sa->get_other_id(this->ike_sa),
auth_method_names, AUTH_EAP);
status = FAILED;
@@ -459,7 +466,7 @@ static status_t build_eap_r(private_ike_auth_t *this, message_t *message)
*/
static status_t build_i(private_ike_auth_t *this, message_t *message)
{
- policy_t *policy;
+ peer_cfg_t *config;
if (message->get_exchange_type(message) == IKE_SA_INIT)
{
@@ -471,8 +478,8 @@ static status_t build_i(private_ike_auth_t *this, message_t *message)
return FAILED;
}
- policy = this->ike_sa->get_policy(this->ike_sa);
- if (policy->get_auth_method(policy) == AUTH_EAP)
+ config = this->ike_sa->get_peer_cfg(this->ike_sa);
+ if (config->get_auth_method(config) == AUTH_EAP)
{
this->eap_auth = eap_authenticator_create(this->ike_sa);
}
@@ -488,10 +495,12 @@ static status_t build_i(private_ike_auth_t *this, message_t *message)
}
/**
- * Implementation of task_t.process for initiator
+ * Implementation of task_t.process for responder
*/
static status_t process_r(private_ike_auth_t *this, message_t *message)
-{
+{
+ peer_cfg_t *config;
+
if (message->get_exchange_type(message) == IKE_SA_INIT)
{
return collect_other_init_data(this, message);
@@ -514,6 +523,17 @@ static status_t process_r(private_ike_auth_t *this, message_t *message)
default:
break;
}
+
+ config = charon->backends->get_peer_cfg(charon->backends,
+ this->ike_sa->get_my_id(this->ike_sa),
+ this->ike_sa->get_other_id(this->ike_sa),
+ this->ike_sa->get_other_ca(this->ike_sa));
+ if (config)
+ {
+ this->ike_sa->set_peer_cfg(this->ike_sa, config);
+ config->destroy(config);
+ }
+
return NEED_MORE;
}
@@ -522,7 +542,7 @@ static status_t process_r(private_ike_auth_t *this, message_t *message)
*/
static status_t build_r(private_ike_auth_t *this, message_t *message)
{
- policy_t *policy;
+ peer_cfg_t *config;
eap_type_t eap_type;
eap_payload_t *eap_payload;
status_t status;
@@ -532,10 +552,12 @@ static status_t build_r(private_ike_auth_t *this, message_t *message)
return collect_my_init_data(this, message);
}
- policy = this->ike_sa->get_policy(this->ike_sa);
- if (policy == NULL)
+ config = this->ike_sa->get_peer_cfg(this->ike_sa);
+ if (config == NULL)
{
- SIG(IKE_UP_FAILED, "no acceptable policy found");
+ SIG(IKE_UP_FAILED, "no matching config found for %D...%D",
+ this->ike_sa->get_my_id(this->ike_sa),
+ this->ike_sa->get_other_id(this->ike_sa));
message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty);
return FAILED;
}
@@ -567,7 +589,7 @@ static status_t build_r(private_ike_auth_t *this, message_t *message)
}
/* initiate EAP authenitcation */
- eap_type = policy->get_eap_type(policy);
+ eap_type = config->get_eap_type(config);
status = this->eap_auth->initiate(this->eap_auth, eap_type, &eap_payload);
message->add_payload(message, (payload_t*)eap_payload);
if (status != NEED_MORE)
diff --git a/src/charon/sa/tasks/ike_cert.c b/src/charon/sa/tasks/ike_cert.c
index 160600742..880ed9c42 100644
--- a/src/charon/sa/tasks/ike_cert.c
+++ b/src/charon/sa/tasks/ike_cert.c
@@ -84,7 +84,7 @@ static void process_certreqs(private_ike_cert_t *this, message_t *message)
encoding = certreq->get_cert_encoding(certreq);
if (encoding != CERT_X509_SIGNATURE)
{
- DBG1(DBG_IKE, "certreq payload %N not supported, ignored",
+ DBG1(DBG_IKE, "certreq payload %N not supported - ignored",
cert_encoding_names, encoding);
continue;
}
@@ -125,7 +125,7 @@ static void process_certs(private_ike_cert_t *this, message_t *message)
encoding = cert_payload->get_cert_encoding(cert_payload);
if (encoding != CERT_X509_SIGNATURE)
{
- DBG1(DBG_IKE, "certificate payload %N not supported, ignored",
+ DBG1(DBG_IKE, "certificate payload %N not supported - ignored",
cert_encoding_names, encoding);
continue;
}
@@ -134,31 +134,29 @@ static void process_certs(private_ike_cert_t *this, message_t *message)
cert = x509_create_from_chunk(cert_data, 0);
if (cert)
{
- if (charon->credentials->verify(charon->credentials,
- cert, &found))
+ if (charon->credentials->verify(charon->credentials, cert, &found))
{
- DBG2(DBG_IKE, "received end entity certificate is trusted, "
- "added to store");
- if (!found)
+ DBG2(DBG_IKE, "received end entity certificate is trusted - "
+ "added to store");
+ if (found)
{
- charon->credentials->add_end_certificate(
- charon->credentials, cert);
+ cert->destroy(cert);
}
else
{
- cert->destroy(cert);
+ charon->credentials->add_end_certificate(charon->credentials, cert);
}
}
else
{
- DBG1(DBG_IKE, "received end entity certificate is not "
- "trusted, discarded");
+ DBG1(DBG_IKE, "received end entity certificate is not trusted - "
+ "discarded");
cert->destroy(cert);
}
}
else
{
- DBG1(DBG_IKE, "parsing of received certificate failed, discarded");
+ DBG1(DBG_IKE, "parsing of received certificate failed - discarded");
chunk_free(&cert_data);
}
}
@@ -171,20 +169,20 @@ static void process_certs(private_ike_cert_t *this, message_t *message)
*/
static void build_certreqs(private_ike_cert_t *this, message_t *message)
{
- connection_t *connection;
- policy_t *policy;
+ ike_cfg_t *ike_cfg;
+ peer_cfg_t *peer_cfg;
identification_t *ca;
certreq_payload_t *certreq;
- connection = this->ike_sa->get_connection(this->ike_sa);
+ ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
- if (connection->get_certreq_policy(connection) != CERT_NEVER_SEND)
+ if (ike_cfg->send_certreq(ike_cfg) != CERT_NEVER_SEND)
{
- policy = this->ike_sa->get_policy(this->ike_sa);
+ peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
- if (policy)
+ if (peer_cfg)
{
- ca = policy->get_other_ca(policy);
+ ca = peer_cfg->get_other_ca(peer_cfg);
if (ca && ca->get_type(ca) != ID_ANY)
{
@@ -212,17 +210,15 @@ static void build_certreqs(private_ike_cert_t *this, message_t *message)
*/
static void build_certs(private_ike_cert_t *this, message_t *message)
{
- policy_t *policy;
- connection_t *connection;
+ peer_cfg_t *peer_cfg;
x509_t *cert;
cert_payload_t *payload;
- policy = this->ike_sa->get_policy(this->ike_sa);
- connection = this->ike_sa->get_connection(this->ike_sa);
+ peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
- if (policy && policy->get_auth_method(policy) == AUTH_RSA)
+ if (peer_cfg && peer_cfg->get_auth_method(peer_cfg) == AUTH_RSA)
{
- switch (connection->get_cert_policy(connection))
+ switch (peer_cfg->get_cert_policy(peer_cfg))
{
case CERT_NEVER_SEND:
break;
@@ -236,7 +232,7 @@ static void build_certs(private_ike_cert_t *this, message_t *message)
{
/* TODO: respect CA cert request */
cert = charon->credentials->get_certificate(charon->credentials,
- policy->get_my_id(policy));
+ peer_cfg->get_my_id(peer_cfg));
if (cert)
{
payload = cert_payload_create_from_x509(cert);
diff --git a/src/charon/sa/tasks/ike_config.c b/src/charon/sa/tasks/ike_config.c
index ce29b9220..3c73395a5 100644
--- a/src/charon/sa/tasks/ike_config.c
+++ b/src/charon/sa/tasks/ike_config.c
@@ -49,11 +49,6 @@ struct private_ike_config_t {
bool initiator;
/**
- * associated policy with virtual IP configuration
- */
- policy_t *policy;
-
- /**
* virtual ip
*/
host_t *virtual_ip;
@@ -266,7 +261,20 @@ static status_t build_i(private_ike_config_t *this, message_t *message)
if (message->get_exchange_type(message) == IKE_AUTH &&
message->get_payload(message, ID_INITIATOR))
{
- this->virtual_ip = this->policy->get_virtual_ip(this->policy, NULL);
+ peer_cfg_t *config;
+ host_t *vip;
+
+ /* reuse virtual IP if we already have one */
+ vip = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
+ if (vip)
+ {
+ this->virtual_ip = vip->clone(vip);
+ }
+ else
+ {
+ config = this->ike_sa->get_peer_cfg(this->ike_sa);
+ this->virtual_ip = config->get_my_virtual_ip(config);
+ }
build_payloads(this, message, CFG_REQUEST);
}
@@ -295,17 +303,18 @@ static status_t build_r(private_ike_config_t *this, message_t *message)
if (message->get_exchange_type(message) == IKE_AUTH &&
message->get_payload(message, EXTENSIBLE_AUTHENTICATION) == NULL)
{
- this->policy = this->ike_sa->get_policy(this->ike_sa);
+ peer_cfg_t *config = this->ike_sa->get_peer_cfg(this->ike_sa);
- if (this->policy && this->virtual_ip)
+ if (config && this->virtual_ip)
{
host_t *ip;
DBG1(DBG_IKE, "peer requested virtual IP %H", this->virtual_ip);
- ip = this->policy->get_virtual_ip(this->policy, this->virtual_ip);
+ ip = config->get_other_virtual_ip(config, this->virtual_ip);
if (ip == NULL || ip->is_anyaddr(ip))
{
DBG1(DBG_IKE, "not assigning a virtual IP to peer");
+ DESTROY_IF(ip);
return SUCCESS;
}
DBG1(DBG_IKE, "assigning virtual IP %H to peer", ip);
@@ -340,13 +349,20 @@ static status_t process_i(private_ike_config_t *this, message_t *message)
!message->get_payload(message, EXTENSIBLE_AUTHENTICATION))
{
host_t *ip;
+ peer_cfg_t *config;
DESTROY_IF(this->virtual_ip);
this->virtual_ip = NULL;
process_payloads(this, message);
+
+ if (this->virtual_ip == NULL)
+ { /* force a configured virtual IP, even server didn't return one */
+ config = this->ike_sa->get_peer_cfg(this->ike_sa);
+ this->virtual_ip = config->get_my_virtual_ip(config);
+ }
- if (this->virtual_ip)
+ if (this->virtual_ip && !this->virtual_ip->is_anyaddr(this->virtual_ip))
{
this->ike_sa->set_virtual_ip(this->ike_sa, TRUE, this->virtual_ip);
@@ -398,7 +414,7 @@ static void destroy(private_ike_config_t *this)
/*
* Described in header.
*/
-ike_config_t *ike_config_create(ike_sa_t *ike_sa, policy_t *policy)
+ike_config_t *ike_config_create(ike_sa_t *ike_sa, bool initiator)
{
private_ike_config_t *this = malloc_thing(private_ike_config_t);
@@ -406,21 +422,18 @@ ike_config_t *ike_config_create(ike_sa_t *ike_sa, policy_t *policy)
this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
this->public.task.destroy = (void(*)(task_t*))destroy;
- if (policy)
+ if (initiator)
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
- this->initiator = TRUE;
}
else
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
- this->initiator = FALSE;
}
-
+ this->initiator = initiator;
this->ike_sa = ike_sa;
- this->policy = policy;
this->virtual_ip = NULL;
this->dns = linked_list_create();
diff --git a/src/charon/sa/tasks/ike_config.h b/src/charon/sa/tasks/ike_config.h
index 0c9b961b4..a7cfddff0 100644
--- a/src/charon/sa/tasks/ike_config.h
+++ b/src/charon/sa/tasks/ike_config.h
@@ -28,7 +28,6 @@ typedef struct ike_config_t ike_config_t;
#include <library.h>
#include <sa/ike_sa.h>
#include <sa/tasks/task.h>
-#include <config/policies/policy.h>
/**
* @brief Task of type IKE_CONFIG, sets up a virtual IP and other
@@ -51,9 +50,9 @@ struct ike_config_t {
* @brief Create a new ike_config task.
*
* @param ike_sa IKE_SA this task works for
- * @param policy policy for the initiator, NULL for the responder
+ * @param initiator TRUE for initiator
* @return ike_config task to handle by the task_manager
*/
-ike_config_t *ike_config_create(ike_sa_t *ike_sa, policy_t *policy);
+ike_config_t *ike_config_create(ike_sa_t *ike_sa, bool initiator);
#endif /* IKE_CONFIG_H_ */
diff --git a/src/charon/sa/tasks/ike_delete.c b/src/charon/sa/tasks/ike_delete.c
index 9c4fdac0e..1a3656ca6 100644
--- a/src/charon/sa/tasks/ike_delete.c
+++ b/src/charon/sa/tasks/ike_delete.c
@@ -28,7 +28,7 @@
typedef struct private_ike_delete_t private_ike_delete_t;
-/**
+/**file
* Private members of a ike_delete_t task.
*/
struct private_ike_delete_t {
@@ -94,7 +94,6 @@ static status_t process_r(private_ike_delete_t *this, message_t *message)
DBG1(DBG_IKE, "deleting IKE_SA on request");
break;
case IKE_REKEYING:
- DBG1(DBG_IKE, "initiated rekeying, but received delete for IKE_SA");
break;
default:
break;
diff --git a/src/charon/sa/tasks/ike_init.c b/src/charon/sa/tasks/ike_init.c
index 0b493666a..f78b5dd66 100644
--- a/src/charon/sa/tasks/ike_init.c
+++ b/src/charon/sa/tasks/ike_init.c
@@ -57,9 +57,9 @@ struct private_ike_init_t {
bool initiator;
/**
- * Connection established by this IKE_SA
+ * IKE config to establish
*/
- connection_t *connection;
+ ike_cfg_t *config;
/**
* diffie hellman group to use
@@ -69,7 +69,7 @@ struct private_ike_init_t {
/**
* Diffie hellman object used to generate public DH value.
*/
- diffie_hellman_t *diffie_hellman;
+ diffie_hellman_t *dh;
/**
* nonce chosen by us
@@ -117,11 +117,11 @@ static void build_payloads(private_ike_init_t *this, message_t *message)
id = this->ike_sa->get_id(this->ike_sa);
- this->connection = this->ike_sa->get_connection(this->ike_sa);
+ this->config = this->ike_sa->get_ike_cfg(this->ike_sa);
if (this->initiator)
{
- proposal_list = this->connection->get_proposals(this->connection);
+ proposal_list = this->config->get_proposals(this->config);
if (this->old_sa)
{
/* include SPI of new IKE_SA when we are rekeying */
@@ -151,7 +151,7 @@ static void build_payloads(private_ike_init_t *this, message_t *message)
nonce_payload->set_nonce(nonce_payload, this->my_nonce);
message->add_payload(message, (payload_t*)nonce_payload);
- ke_payload = ke_payload_create_from_diffie_hellman(this->diffie_hellman);
+ ke_payload = ke_payload_create_from_diffie_hellman(this->dh);
message->add_payload(message, (payload_t*)ke_payload);
}
@@ -174,8 +174,8 @@ static void process_payloads(private_ike_init_t *this, message_t *message)
linked_list_t *proposal_list;
proposal_list = sa_payload->get_proposals(sa_payload);
- this->proposal = this->connection->select_proposal(
- this->connection, proposal_list);
+ this->proposal = this->config->select_proposal(this->config,
+ proposal_list);
proposal_list->destroy_offset(proposal_list,
offsetof(proposal_t, destroy));
break;
@@ -183,34 +183,16 @@ static void process_payloads(private_ike_init_t *this, message_t *message)
case KEY_EXCHANGE:
{
ke_payload_t *ke_payload = (ke_payload_t*)payload;
- diffie_hellman_group_t dh_group;
- chunk_t key_data;
- dh_group = ke_payload->get_dh_group_number(ke_payload);
-
- if (this->initiator)
+ this->dh_group = ke_payload->get_dh_group_number(ke_payload);
+ if (!this->initiator)
{
- if (dh_group != this->dh_group)
- {
- DBG1(DBG_IKE, "received a DH group not requested (%N)",
- diffie_hellman_group_names, dh_group);
- break;
- }
+ this->dh = diffie_hellman_create(this->dh_group);
}
- else
+ if (this->dh)
{
- this->dh_group = dh_group;
- if (!this->connection->check_dh_group(this->connection,
- dh_group))
- {
- break;
- }
- this->diffie_hellman = diffie_hellman_create(dh_group);
- }
- if (this->diffie_hellman)
- {
- key_data = ke_payload->get_key_exchange_data(ke_payload);
- this->diffie_hellman->set_other_public_value(this->diffie_hellman, key_data);
+ this->dh->set_other_public_value(this->dh,
+ ke_payload->get_key_exchange_data(ke_payload));
}
break;
}
@@ -235,9 +217,9 @@ static status_t build_i(private_ike_init_t *this, message_t *message)
randomizer_t *randomizer;
status_t status;
- this->connection = this->ike_sa->get_connection(this->ike_sa);
+ this->config = this->ike_sa->get_ike_cfg(this->ike_sa);
SIG(IKE_UP_START, "initiating IKE_SA to %H",
- this->connection->get_other_host(this->connection));
+ this->config->get_other_host(this->config));
this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING);
if (this->retry++ >= MAX_RETRIES)
@@ -247,11 +229,11 @@ static status_t build_i(private_ike_init_t *this, message_t *message)
}
/* if the DH group is set via use_dh_group(), we already have a DH object */
- if (!this->diffie_hellman)
+ if (!this->dh)
{
- this->dh_group = this->connection->get_dh_group(this->connection);
- this->diffie_hellman = diffie_hellman_create(this->dh_group);
- if (this->diffie_hellman == NULL)
+ this->dh_group = this->config->get_dh_group(this->config);
+ this->dh = diffie_hellman_create(this->dh_group);
+ if (this->dh == NULL)
{
SIG(IKE_UP_FAILED, "configured DH group %N not supported",
diffie_hellman_group_names, this->dh_group);
@@ -291,7 +273,7 @@ static status_t process_r(private_ike_init_t *this, message_t *message)
{
randomizer_t *randomizer;
- this->connection = this->ike_sa->get_connection(this->ike_sa);
+ this->config = this->ike_sa->get_ike_cfg(this->ike_sa);
SIG(IKE_UP_FAILED, "%H is initiating an IKE_SA",
message->get_source(message));
this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING);
@@ -326,25 +308,29 @@ static status_t build_r(private_ike_init_t *this, message_t *message)
return FAILED;
}
- if (this->diffie_hellman == NULL ||
- this->diffie_hellman->get_shared_secret(this->diffie_hellman,
- &secret) != SUCCESS)
+ if (this->dh == NULL ||
+ !this->proposal->has_dh_group(this->proposal, this->dh_group) ||
+ this->dh->get_shared_secret(this->dh, &secret) != SUCCESS)
{
- chunk_t chunk;
- u_int16_t dh_enc;
-
- SIG(IKE_UP_FAILED, "received inacceptable DH group (%N)",
- diffie_hellman_group_names, this->dh_group);
- this->dh_group = this->connection->get_dh_group(this->connection);
- dh_enc = htons(this->dh_group);
- chunk.ptr = (u_int8_t*)&dh_enc;
- chunk.len = sizeof(dh_enc);
- message->add_notify(message, TRUE, INVALID_KE_PAYLOAD, chunk);
- DBG1(DBG_IKE, "requesting DH group %N",
- diffie_hellman_group_names, this->dh_group);
+ algorithm_t *algo;
+ if (this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP,
+ &algo))
+ {
+ u_int16_t group = algo->algorithm;
+ SIG(CHILD_UP_FAILED, "DH group %N inacceptable, requesting %N",
+ diffie_hellman_group_names, this->dh_group,
+ diffie_hellman_group_names, group);
+ this->dh_group = group;
+ group = htons(group);
+ message->add_notify(message, FALSE, INVALID_KE_PAYLOAD,
+ chunk_from_thing(group));
+ }
+ else
+ {
+ SIG(IKE_UP_FAILED, "no acceptable proposal found");
+ }
return FAILED;
}
-
if (this->old_sa)
{
@@ -405,27 +391,20 @@ static status_t process_i(private_ike_init_t *this, message_t *message)
case INVALID_KE_PAYLOAD:
{
chunk_t data;
- diffie_hellman_group_t old_dh_group;
+ diffie_hellman_group_t bad_group;
- old_dh_group = this->dh_group;
+ bad_group = this->dh_group;
data = notify->get_notification_data(notify);
this->dh_group = ntohs(*((u_int16_t*)data.ptr));
-
- DBG1(DBG_IKE, "peer didn't accept DH group %N, it requested"
- " %N", diffie_hellman_group_names, old_dh_group,
- diffie_hellman_group_names, this->dh_group);
- if (!this->connection->check_dh_group(this->connection,
- this->dh_group))
- {
- DBG1(DBG_IKE, "requested DH group %N not acceptable, "
- "giving up", diffie_hellman_group_names,
- this->dh_group);
- iterator->destroy(iterator);
- return FAILED;
+ DBG1(DBG_IKE, "peer didn't accept DH group %N, "
+ "it requested %N", diffie_hellman_group_names,
+ bad_group, diffie_hellman_group_names, this->dh_group);
+
+ if (this->old_sa == NULL)
+ { /* reset the IKE_SA if we are not rekeying */
+ this->ike_sa->reset(this->ike_sa);
}
- this->ike_sa->reset(this->ike_sa);
-
iterator->destroy(iterator);
return NEED_MORE;
}
@@ -470,9 +449,9 @@ static status_t process_i(private_ike_init_t *this, message_t *message)
return FAILED;
}
- if (this->diffie_hellman == NULL ||
- this->diffie_hellman->get_shared_secret(this->diffie_hellman,
- &secret) != SUCCESS)
+ if (this->dh == NULL ||
+ !this->proposal->has_dh_group(this->proposal, this->dh_group) ||
+ this->dh->get_shared_secret(this->dh, &secret) != SUCCESS)
{
SIG(IKE_UP_FAILED, "peers DH group selection invalid");
return FAILED;
@@ -539,12 +518,12 @@ static chunk_t get_lower_nonce(private_ike_init_t *this)
static void migrate(private_ike_init_t *this, ike_sa_t *ike_sa)
{
DESTROY_IF(this->proposal);
- DESTROY_IF(this->diffie_hellman);
+ DESTROY_IF(this->dh);
chunk_free(&this->other_nonce);
this->ike_sa = ike_sa;
this->proposal = NULL;
- this->diffie_hellman = diffie_hellman_create(this->dh_group);
+ this->dh = diffie_hellman_create(this->dh_group);
}
/**
@@ -553,7 +532,7 @@ static void migrate(private_ike_init_t *this, ike_sa_t *ike_sa)
static void destroy(private_ike_init_t *this)
{
DESTROY_IF(this->proposal);
- DESTROY_IF(this->diffie_hellman);
+ DESTROY_IF(this->dh);
chunk_free(&this->my_nonce);
chunk_free(&this->other_nonce);
chunk_free(&this->cookie);
@@ -585,12 +564,12 @@ ike_init_t *ike_init_create(ike_sa_t *ike_sa, bool initiator, ike_sa_t *old_sa)
this->ike_sa = ike_sa;
this->initiator = initiator;
this->dh_group = MODP_NONE;
- this->diffie_hellman = NULL;
+ this->dh = NULL;
this->my_nonce = chunk_empty;
this->other_nonce = chunk_empty;
this->cookie = chunk_empty;
this->proposal = NULL;
- this->connection = NULL;
+ this->config = NULL;
this->old_sa = old_sa;
this->retry = 0;
diff --git a/src/charon/sa/tasks/ike_rekey.c b/src/charon/sa/tasks/ike_rekey.c
index a33e7ee34..d54fc3524 100644
--- a/src/charon/sa/tasks/ike_rekey.c
+++ b/src/charon/sa/tasks/ike_rekey.c
@@ -26,8 +26,8 @@
#include <daemon.h>
#include <encoding/payloads/notify_payload.h>
#include <sa/tasks/ike_init.h>
-#include <queues/jobs/delete_ike_sa_job.h>
-#include <queues/jobs/rekey_ike_sa_job.h>
+#include <processing/jobs/delete_ike_sa_job.h>
+#include <processing/jobs/rekey_ike_sa_job.h>
typedef struct private_ike_rekey_t private_ike_rekey_t;
@@ -73,21 +73,20 @@ struct private_ike_rekey_t {
*/
static status_t build_i(private_ike_rekey_t *this, message_t *message)
{
- connection_t *connection;
- policy_t *policy;
+ peer_cfg_t *peer_cfg;
- this->new_sa = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager,
- TRUE);
-
- connection = this->ike_sa->get_connection(this->ike_sa);
- policy = this->ike_sa->get_policy(this->ike_sa);
- this->new_sa->set_connection(this->new_sa, connection);
- this->new_sa->set_policy(this->new_sa, policy);
-
- this->ike_init = ike_init_create(this->new_sa, TRUE, this->ike_sa);
+ /* create new SA only on first try */
+ if (this->new_sa == NULL)
+ {
+ this->new_sa = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager,
+ TRUE);
+
+ peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
+ this->new_sa->set_peer_cfg(this->new_sa, peer_cfg);
+ this->ike_init = ike_init_create(this->new_sa, TRUE, this->ike_sa);
+ this->ike_sa->set_state(this->ike_sa, IKE_REKEYING);
+ }
this->ike_init->task.build(&this->ike_init->task, message);
-
- this->ike_sa->set_state(this->ike_sa, IKE_REKEYING);
return NEED_MORE;
}
@@ -97,8 +96,7 @@ static status_t build_i(private_ike_rekey_t *this, message_t *message)
*/
static status_t process_r(private_ike_rekey_t *this, message_t *message)
{
- connection_t *connection;
- policy_t *policy;
+ peer_cfg_t *peer_cfg;
iterator_t *iterator;
child_sa_t *child_sa;
@@ -129,11 +127,8 @@ static status_t process_r(private_ike_rekey_t *this, message_t *message)
this->new_sa = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager,
FALSE);
- connection = this->ike_sa->get_connection(this->ike_sa);
- policy = this->ike_sa->get_policy(this->ike_sa);
- this->new_sa->set_connection(this->new_sa, connection);
- this->new_sa->set_policy(this->new_sa, policy);
-
+ peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
+ this->new_sa->set_peer_cfg(this->new_sa, peer_cfg);
this->ike_init = ike_init_create(this->new_sa, FALSE, this->ike_sa);
this->ike_init->task.process(&this->ike_init->task, message);
@@ -171,23 +166,29 @@ static status_t process_i(private_ike_rekey_t *this, message_t *message)
job_t *job;
ike_sa_id_t *to_delete;
- if (this->ike_init->task.process(&this->ike_init->task, message) == FAILED)
+ switch (this->ike_init->task.process(&this->ike_init->task, message))
{
- /* rekeying failed, fallback to old SA */
- if (!(this->collision &&
- this->collision->get_type(this->collision) == IKE_DELETE))
- {
- job_t *job;
- u_int32_t retry = charon->configuration->get_retry_interval(
- charon->configuration);
- job = (job_t*)rekey_ike_sa_job_create(
- this->ike_sa->get_id(this->ike_sa), FALSE);
- DBG1(DBG_IKE, "IKE_SA rekeying failed, "
- "trying again in %d seconds", retry);
- this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
- charon->event_queue->add_relative(charon->event_queue, job, retry * 1000);
- }
- return SUCCESS;
+ case FAILED:
+ /* rekeying failed, fallback to old SA */
+ if (!(this->collision &&
+ this->collision->get_type(this->collision) == IKE_DELETE))
+ {
+ job_t *job;
+ u_int32_t retry = RETRY_INTERVAL - (random() % RETRY_JITTER);
+ job = (job_t*)rekey_ike_sa_job_create(
+ this->ike_sa->get_id(this->ike_sa), FALSE);
+ DBG1(DBG_IKE, "IKE_SA rekeying failed, "
+ "trying again in %d seconds", retry);
+ this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
+ charon->event_queue->add_relative(charon->event_queue, job, retry * 1000);
+ }
+ return SUCCESS;
+ case NEED_MORE:
+ /* bad dh group, try again */
+ this->ike_init->task.migrate(&this->ike_init->task, this->new_sa);
+ return NEED_MORE;
+ default:
+ break;
}
this->new_sa->set_state(this->new_sa, IKE_ESTABLISHED);