summaryrefslogtreecommitdiff
path: root/src/libcharon/sa/ikev2
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcharon/sa/ikev2')
-rw-r--r--src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c23
-rw-r--r--src/libcharon/sa/ikev2/task_manager_v2.c102
-rw-r--r--src/libcharon/sa/ikev2/tasks/child_create.c7
-rw-r--r--src/libcharon/sa/ikev2/tasks/child_rekey.c11
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_auth.c144
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_config.c5
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_init.c146
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_me.c5
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_mobike.c13
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_natd.c9
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_redirect.c150
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_redirect.h54
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_vendor.c56
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_verify_peer_cert.c117
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_verify_peer_cert.h54
15 files changed, 797 insertions, 99 deletions
diff --git a/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c b/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c
index 2284a484d..04ccd4f4f 100644
--- a/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c
+++ b/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c
@@ -55,11 +55,6 @@ struct private_pubkey_authenticator_t {
* Reserved bytes of ID payload
*/
char reserved[3];
-
- /**
- * Whether to store signature schemes on remote auth configs.
- */
- bool store_signature_scheme;
};
/**
@@ -130,7 +125,7 @@ static array_t *select_signature_schemes(keymat_v2_t *keymat,
enumerator = auth->create_enumerator(auth);
while (enumerator->enumerate(enumerator, &rule, &config))
{
- if (rule != AUTH_RULE_SIGNATURE_SCHEME)
+ if (rule != AUTH_RULE_IKE_SIGNATURE_SCHEME)
{
continue;
}
@@ -369,6 +364,8 @@ METHOD(authenticator_t, process, status_t,
signature_scheme_t scheme;
status_t status = NOT_FOUND;
keymat_v2_t *keymat;
+ const char *reason = "unsupported";
+ bool online;
auth_payload = (auth_payload_t*)message->get_payload(message, PLV2_AUTH);
if (!auth_payload)
@@ -397,8 +394,11 @@ METHOD(authenticator_t, process, status_t,
{
break;
}
+ reason = "payload invalid";
/* fall-through */
default:
+ DBG1(DBG_IKE, "%N authentication %s", auth_method_names,
+ auth_method, reason);
return INVALID_ARG;
}
id = this->ike_sa->get_other_id(this->ike_sa);
@@ -409,8 +409,10 @@ METHOD(authenticator_t, process, status_t,
return FAILED;
}
auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
+ online = !this->ike_sa->has_condition(this->ike_sa,
+ COND_ONLINE_VALIDATION_SUSPENDED);
enumerator = lib->credmgr->create_public_enumerator(lib->credmgr,
- key_type, id, auth);
+ key_type, id, auth, online);
while (enumerator->enumerate(enumerator, &public, &current_auth))
{
if (public->verify(public, scheme, octets, auth_data))
@@ -421,9 +423,10 @@ METHOD(authenticator_t, process, status_t,
status = SUCCESS;
auth->merge(auth, current_auth, FALSE);
auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
- if (this->store_signature_scheme)
+ auth->add(auth, AUTH_RULE_IKE_SIGNATURE_SCHEME, (uintptr_t)scheme);
+ if (!online)
{
- auth->add(auth, AUTH_RULE_SIGNATURE_SCHEME, (uintptr_t)scheme);
+ auth->add(auth, AUTH_RULE_CERT_VALIDATION_SUSPENDED, TRUE);
}
break;
}
@@ -497,8 +500,6 @@ pubkey_authenticator_t *pubkey_authenticator_create_verifier(ike_sa_t *ike_sa,
.ike_sa = ike_sa,
.ike_sa_init = received_init,
.nonce = sent_nonce,
- .store_signature_scheme = lib->settings->get_bool(lib->settings,
- "%s.signature_authentication_constraints", TRUE, lib->ns),
);
memcpy(this->reserved, reserved, sizeof(this->reserved));
diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c
index 4676867df..c2f972ab1 100644
--- a/src/libcharon/sa/ikev2/task_manager_v2.c
+++ b/src/libcharon/sa/ikev2/task_manager_v2.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007-2014 Tobias Brunner
+ * Copyright (C) 2007-2015 Tobias Brunner
* Copyright (C) 2007-2010 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -30,10 +30,12 @@
#include <sa/ikev2/tasks/ike_rekey.h>
#include <sa/ikev2/tasks/ike_reauth.h>
#include <sa/ikev2/tasks/ike_reauth_complete.h>
+#include <sa/ikev2/tasks/ike_redirect.h>
#include <sa/ikev2/tasks/ike_delete.h>
#include <sa/ikev2/tasks/ike_config.h>
#include <sa/ikev2/tasks/ike_dpd.h>
#include <sa/ikev2/tasks/ike_vendor.h>
+#include <sa/ikev2/tasks/ike_verify_peer_cert.h>
#include <sa/ikev2/tasks/child_create.h>
#include <sa/ikev2/tasks/child_rekey.h>
#include <sa/ikev2/tasks/child_delete.h>
@@ -474,6 +476,11 @@ METHOD(task_manager_t, initiate, status_t,
exchange = INFORMATIONAL;
break;
}
+ if (activate_task(this, TASK_IKE_REDIRECT))
+ {
+ exchange = INFORMATIONAL;
+ break;
+ }
if (activate_task(this, TASK_CHILD_DELETE))
{
exchange = INFORMATIONAL;
@@ -521,6 +528,11 @@ METHOD(task_manager_t, initiate, status_t,
exchange = INFORMATIONAL;
break;
}
+ if (activate_task(this, TASK_IKE_VERIFY_PEER_CERT))
+ {
+ exchange = INFORMATIONAL;
+ break;
+ }
case IKE_REKEYING:
if (activate_task(this, TASK_IKE_DELETE))
{
@@ -618,7 +630,7 @@ METHOD(task_manager_t, initiate, status_t,
if (this->initiating.type == EXCHANGE_TYPE_UNDEFINED)
{
message->destroy(message);
- return SUCCESS;
+ return initiate(this);
}
if (!generate_message(this, message, &this->initiating.packets))
@@ -656,6 +668,32 @@ static status_t process_response(private_task_manager_t *this,
return DESTROY_ME;
}
+ enumerator = array_create_enumerator(this->active_tasks);
+ while (enumerator->enumerate(enumerator, &task))
+ {
+ if (!task->pre_process)
+ {
+ continue;
+ }
+ switch (task->pre_process(task, message))
+ {
+ case SUCCESS:
+ break;
+ case FAILED:
+ default:
+ /* just ignore the message */
+ DBG1(DBG_IKE, "ignore invalid %N response",
+ exchange_type_names, message->get_exchange_type(message));
+ enumerator->destroy(enumerator);
+ return SUCCESS;
+ case DESTROY_ME:
+ /* critical failure, destroy IKE_SA */
+ enumerator->destroy(enumerator);
+ return DESTROY_ME;
+ }
+ }
+ enumerator->destroy(enumerator);
+
/* catch if we get resetted while processing */
this->reset = FALSE;
enumerator = array_create_enumerator(this->active_tasks);
@@ -992,6 +1030,11 @@ static status_t process_request(private_task_manager_t *this,
* invokes all the required hooks. */
task = (task_t*)ike_delete_create(
this->ike_sa, FALSE);
+ break;
+ case REDIRECT:
+ task = (task_t*)ike_redirect_create(
+ this->ike_sa, NULL);
+ break;
default:
break;
}
@@ -1041,6 +1084,44 @@ static status_t process_request(private_task_manager_t *this,
}
}
+ enumerator = array_create_enumerator(this->passive_tasks);
+ while (enumerator->enumerate(enumerator, &task))
+ {
+ if (!task->pre_process)
+ {
+ continue;
+ }
+ switch (task->pre_process(task, message))
+ {
+ case SUCCESS:
+ break;
+ case FAILED:
+ default:
+ /* just ignore the message */
+ DBG1(DBG_IKE, "ignore invalid %N request",
+ exchange_type_names, message->get_exchange_type(message));
+ enumerator->destroy(enumerator);
+ switch (message->get_exchange_type(message))
+ {
+ case IKE_SA_INIT:
+ /* no point in keeping the SA when it was created with
+ * an invalid IKE_SA_INIT message */
+ return DESTROY_ME;
+ default:
+ /* remove tasks we queued for this request */
+ flush_queue(this, TASK_QUEUE_PASSIVE);
+ /* fall-through */
+ case IKE_AUTH:
+ return NEED_MORE;
+ }
+ case DESTROY_ME:
+ /* critical failure, destroy IKE_SA */
+ enumerator->destroy(enumerator);
+ return DESTROY_ME;
+ }
+ }
+ enumerator->destroy(enumerator);
+
/* let the tasks process the message */
enumerator = array_create_enumerator(this->passive_tasks);
while (enumerator->enumerate(enumerator, (void*)&task))
@@ -1331,12 +1412,17 @@ METHOD(task_manager_t, process_message, status_t,
{ /* ignore messages altered to EXCHANGE_TYPE_UNDEFINED */
return SUCCESS;
}
- if (process_request(this, msg) != SUCCESS)
+ switch (process_request(this, msg))
{
- flush(this);
- return DESTROY_ME;
+ case SUCCESS:
+ this->responding.mid++;
+ break;
+ case NEED_MORE:
+ break;
+ default:
+ flush(this);
+ return DESTROY_ME;
}
- this->responding.mid++;
}
else if ((mid == this->responding.mid - 1) &&
array_count(this->responding.packets))
@@ -1570,8 +1656,12 @@ static void trigger_mbb_reauth(private_task_manager_t *this)
}
enumerator->destroy(enumerator);
+ /* suspend online revocation checking until the SA is established */
+ new->set_condition(new, COND_ONLINE_VALIDATION_SUSPENDED, TRUE);
+
if (new->initiate(new, NULL, 0, NULL, NULL) != DESTROY_ME)
{
+ new->queue_task(new, (task_t*)ike_verify_peer_cert_create(new));
new->queue_task(new, (task_t*)ike_reauth_complete_create(new,
this->ike_sa->get_id(this->ike_sa)));
charon->ike_sa_manager->checkin(charon->ike_sa_manager, new);
diff --git a/src/libcharon/sa/ikev2/tasks/child_create.c b/src/libcharon/sa/ikev2/tasks/child_create.c
index 97f73d851..3d4ded944 100644
--- a/src/libcharon/sa/ikev2/tasks/child_create.c
+++ b/src/libcharon/sa/ikev2/tasks/child_create.c
@@ -18,7 +18,6 @@
#include "child_create.h"
#include <daemon.h>
-#include <hydra.h>
#include <sa/ikev2/keymat_v2.h>
#include <crypto/diffie_hellman.h>
#include <credentials/certificates/x509.h>
@@ -786,7 +785,7 @@ static bool build_payloads(private_child_create_t *this, message_t *message)
break;
}
- features = hydra->kernel_interface->get_features(hydra->kernel_interface);
+ features = charon->kernel->get_features(charon->kernel);
if (!(features & KERNEL_ESP_V3_TFC))
{
message->add_notify(message, FALSE, ESP_TFC_PADDING_NOT_SUPPORTED,
@@ -1221,6 +1220,10 @@ METHOD(task_t, build_r, status_t,
{ /* wait until all authentication round completed */
return NEED_MORE;
}
+ if (this->ike_sa->has_condition(this->ike_sa, COND_REDIRECTED))
+ { /* no CHILD_SA is created for redirected SAs */
+ return SUCCESS;
+ }
ike_auth = TRUE;
default:
break;
diff --git a/src/libcharon/sa/ikev2/tasks/child_rekey.c b/src/libcharon/sa/ikev2/tasks/child_rekey.c
index c7a8a1342..6f0c2b2c7 100644
--- a/src/libcharon/sa/ikev2/tasks/child_rekey.c
+++ b/src/libcharon/sa/ikev2/tasks/child_rekey.c
@@ -279,11 +279,15 @@ static child_sa_t *handle_collision(private_child_rekey_t *this)
/* don't touch child other created, it has already been deleted */
if (!this->other_child_destroyed)
{
- /* disable close action for the redundand child */
+ /* disable close action and updown event for redundant child */
child_sa = other->child_create->get_child(other->child_create);
if (child_sa)
{
child_sa->set_close_action(child_sa, ACTION_NONE);
+ if (child_sa->get_state(child_sa) != CHILD_REKEYING)
+ {
+ child_sa->set_state(child_sa, CHILD_REKEYING);
+ }
}
}
}
@@ -372,6 +376,11 @@ METHOD(task_t, process_i, status_t,
{
return SUCCESS;
}
+ /* disable updown event for redundant CHILD_SA */
+ if (to_delete->get_state(to_delete) != CHILD_REKEYING)
+ {
+ to_delete->set_state(to_delete, CHILD_REKEYING);
+ }
spi = to_delete->get_spi(to_delete, TRUE);
protocol = to_delete->get_protocol(to_delete);
diff --git a/src/libcharon/sa/ikev2/tasks/ike_auth.c b/src/libcharon/sa/ikev2/tasks/ike_auth.c
index 2554496c1..79a436fbf 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_auth.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_auth.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Tobias Brunner
+ * Copyright (C) 2012-2015 Tobias Brunner
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
@@ -25,6 +25,7 @@
#include <encoding/payloads/eap_payload.h>
#include <encoding/payloads/nonce_payload.h>
#include <sa/ikev2/authenticators/eap_authenticator.h>
+#include <processing/jobs/delete_ike_sa_job.h>
typedef struct private_ike_auth_t private_ike_auth_t;
@@ -117,6 +118,11 @@ struct private_ike_auth_t {
* Is EAP acceptable, did we strictly authenticate peer?
*/
bool eap_acceptable;
+
+ /**
+ * Gateway ID if redirected
+ */
+ identification_t *redirect_to;
};
/**
@@ -685,6 +691,7 @@ METHOD(task_t, process_r, status_t,
METHOD(task_t, build_r, status_t,
private_ike_auth_t *this, message_t *message)
{
+ identification_t *gateway;
auth_cfg_t *cfg;
if (message->get_exchange_type(message) == IKE_SA_INIT)
@@ -817,34 +824,56 @@ METHOD(task_t, build_r, status_t,
{
this->do_another_auth = FALSE;
}
- if (!this->do_another_auth && !this->expect_another_auth)
+ if (this->do_another_auth || this->expect_another_auth)
{
- if (charon->ike_sa_manager->check_uniqueness(charon->ike_sa_manager,
- this->ike_sa, FALSE))
- {
- DBG1(DBG_IKE, "cancelling IKE_SA setup due to uniqueness policy");
- charon->bus->alert(charon->bus, ALERT_UNIQUE_KEEP);
- message->add_notify(message, TRUE, AUTHENTICATION_FAILED,
- chunk_empty);
- return FAILED;
- }
- if (!charon->bus->authorize(charon->bus, TRUE))
- {
- DBG1(DBG_IKE, "final authorization hook forbids IKE_SA, cancelling");
- goto peer_auth_failed;
- }
- DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]",
- this->ike_sa->get_name(this->ike_sa),
- this->ike_sa->get_unique_id(this->ike_sa),
- this->ike_sa->get_my_host(this->ike_sa),
- this->ike_sa->get_my_id(this->ike_sa),
- this->ike_sa->get_other_host(this->ike_sa),
- this->ike_sa->get_other_id(this->ike_sa));
- this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
- charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE);
- return SUCCESS;
+ return NEED_MORE;
}
- return NEED_MORE;
+
+ if (charon->ike_sa_manager->check_uniqueness(charon->ike_sa_manager,
+ this->ike_sa, FALSE))
+ {
+ DBG1(DBG_IKE, "cancelling IKE_SA setup due to uniqueness policy");
+ charon->bus->alert(charon->bus, ALERT_UNIQUE_KEEP);
+ message->add_notify(message, TRUE, AUTHENTICATION_FAILED,
+ chunk_empty);
+ return FAILED;
+ }
+ if (!charon->bus->authorize(charon->bus, TRUE))
+ {
+ DBG1(DBG_IKE, "final authorization hook forbids IKE_SA, cancelling");
+ goto peer_auth_failed;
+ }
+ if (this->ike_sa->supports_extension(this->ike_sa, EXT_IKE_REDIRECTION) &&
+ charon->redirect->redirect_on_auth(charon->redirect, this->ike_sa,
+ &gateway))
+ {
+ delete_ike_sa_job_t *job;
+ chunk_t data;
+
+ DBG1(DBG_IKE, "redirecting peer to %Y", gateway);
+ data = redirect_data_create(gateway, chunk_empty);
+ message->add_notify(message, FALSE, REDIRECT, data);
+ gateway->destroy(gateway);
+ chunk_free(&data);
+ /* we use this condition to prevent the CHILD_SA from getting created */
+ this->ike_sa->set_condition(this->ike_sa, COND_REDIRECTED, TRUE);
+ /* if the peer does not delete the SA we do so after a while */
+ job = delete_ike_sa_job_create(this->ike_sa->get_id(this->ike_sa), TRUE);
+ lib->scheduler->schedule_job(lib->scheduler, (job_t*)job,
+ lib->settings->get_int(lib->settings,
+ "%s.half_open_timeout", HALF_OPEN_IKE_SA_TIMEOUT,
+ lib->ns));
+ }
+ DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]",
+ this->ike_sa->get_name(this->ike_sa),
+ this->ike_sa->get_unique_id(this->ike_sa),
+ this->ike_sa->get_my_host(this->ike_sa),
+ this->ike_sa->get_my_id(this->ike_sa),
+ this->ike_sa->get_other_host(this->ike_sa),
+ this->ike_sa->get_other_id(this->ike_sa));
+ this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
+ charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE);
+ return SUCCESS;
peer_auth_failed:
message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty);
@@ -964,6 +993,15 @@ METHOD(task_t, process_i, status_t,
case ME_ENDPOINT:
/* handled in ike_me task */
break;
+ case REDIRECT:
+ DESTROY_IF(this->redirect_to);
+ this->redirect_to = redirect_data_parse(
+ notify->get_notification_data(notify), NULL);
+ if (!this->redirect_to)
+ {
+ DBG1(DBG_IKE, "received invalid REDIRECT notify");
+ }
+ break;
default:
{
if (type <= 16383)
@@ -1094,30 +1132,35 @@ METHOD(task_t, process_i, status_t,
{
this->expect_another_auth = FALSE;
}
- if (!this->expect_another_auth && !this->do_another_auth && !this->my_auth)
+ if (this->expect_another_auth || this->do_another_auth || this->my_auth)
{
- if (!update_cfg_candidates(this, TRUE))
- {
- goto peer_auth_failed;
- }
- if (!charon->bus->authorize(charon->bus, TRUE))
- {
- DBG1(DBG_IKE, "final authorization hook forbids IKE_SA, "
- "cancelling");
- goto peer_auth_failed;
- }
- DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]",
- this->ike_sa->get_name(this->ike_sa),
- this->ike_sa->get_unique_id(this->ike_sa),
- this->ike_sa->get_my_host(this->ike_sa),
- this->ike_sa->get_my_id(this->ike_sa),
- this->ike_sa->get_other_host(this->ike_sa),
- this->ike_sa->get_other_id(this->ike_sa));
- this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
- charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE);
- return SUCCESS;
+ return NEED_MORE;
}
- return NEED_MORE;
+ if (!update_cfg_candidates(this, TRUE))
+ {
+ goto peer_auth_failed;
+ }
+ if (!charon->bus->authorize(charon->bus, TRUE))
+ {
+ DBG1(DBG_IKE, "final authorization hook forbids IKE_SA, "
+ "cancelling");
+ goto peer_auth_failed;
+ }
+ DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]",
+ this->ike_sa->get_name(this->ike_sa),
+ this->ike_sa->get_unique_id(this->ike_sa),
+ this->ike_sa->get_my_host(this->ike_sa),
+ this->ike_sa->get_my_id(this->ike_sa),
+ this->ike_sa->get_other_host(this->ike_sa),
+ this->ike_sa->get_other_id(this->ike_sa));
+ this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
+ charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE);
+
+ if (this->redirect_to)
+ {
+ this->ike_sa->handle_redirect(this->ike_sa, this->redirect_to);
+ }
+ return SUCCESS;
peer_auth_failed:
charon->bus->alert(charon->bus, ALERT_PEER_AUTH_FAILED);
@@ -1141,6 +1184,7 @@ METHOD(task_t, migrate, void,
DESTROY_IF(this->peer_cfg);
DESTROY_IF(this->my_auth);
DESTROY_IF(this->other_auth);
+ DESTROY_IF(this->redirect_to);
this->candidates->destroy_offset(this->candidates, offsetof(peer_cfg_t, destroy));
this->my_packet = NULL;
@@ -1149,6 +1193,7 @@ METHOD(task_t, migrate, void,
this->peer_cfg = NULL;
this->my_auth = NULL;
this->other_auth = NULL;
+ this->redirect_to = NULL;
this->do_another_auth = TRUE;
this->expect_another_auth = TRUE;
this->authentication_failed = FALSE;
@@ -1165,6 +1210,7 @@ METHOD(task_t, destroy, void,
DESTROY_IF(this->my_auth);
DESTROY_IF(this->other_auth);
DESTROY_IF(this->peer_cfg);
+ DESTROY_IF(this->redirect_to);
this->candidates->destroy_offset(this->candidates, offsetof(peer_cfg_t, destroy));
free(this);
}
diff --git a/src/libcharon/sa/ikev2/tasks/ike_config.c b/src/libcharon/sa/ikev2/tasks/ike_config.c
index 646f20c61..6c42b81a6 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_config.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_config.c
@@ -333,6 +333,11 @@ METHOD(task_t, build_r, status_t,
linked_list_t *vips, *pools;
host_t *requested;
+ if (this->ike_sa->has_condition(this->ike_sa, COND_REDIRECTED))
+ { /* don't assign attributes for redirected SAs */
+ return SUCCESS;
+ }
+
id = this->ike_sa->get_other_eap_id(this->ike_sa);
config = this->ike_sa->get_peer_cfg(this->ike_sa);
vips = linked_list_create();
diff --git a/src/libcharon/sa/ikev2/tasks/ike_init.c b/src/libcharon/sa/ikev2/tasks/ike_init.c
index 1ff643d62..78579be95 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_init.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_init.c
@@ -118,6 +118,11 @@ struct private_ike_init_t {
* Whether to use Signature Authentication as per RFC 7427
*/
bool signature_authentication;
+
+ /**
+ * Whether to follow IKEv2 redirects as per RFC 5685
+ */
+ bool follow_redirects;
};
/**
@@ -166,7 +171,7 @@ static void send_supported_hash_algorithms(private_ike_init_t *this,
enumerator = auth->create_enumerator(auth);
while (enumerator->enumerate(enumerator, &rule, &config))
{
- if (rule == AUTH_RULE_SIGNATURE_SCHEME)
+ if (rule == AUTH_RULE_IKE_SIGNATURE_SCHEME)
{
hash = hasher_from_signature_scheme(config);
if (hasher_algorithm_for_ikev2(hash))
@@ -324,6 +329,29 @@ static bool build_payloads(private_ike_init_t *this, message_t *message)
send_supported_hash_algorithms(this, message);
}
}
+ /* notify other peer if we support redirection */
+ if (!this->old_sa && this->initiator && this->follow_redirects)
+ {
+ identification_t *gateway;
+ host_t *from;
+ chunk_t data;
+
+ from = this->ike_sa->get_redirected_from(this->ike_sa);
+ if (from)
+ {
+ gateway = identification_create_from_sockaddr(
+ from->get_sockaddr(from));
+ data = redirect_data_create(gateway, chunk_empty);
+ message->add_notify(message, FALSE, REDIRECTED_FROM, data);
+ chunk_free(&data);
+ gateway->destroy(gateway);
+ }
+ else
+ {
+ message->add_notify(message, FALSE, REDIRECT_SUPPORTED,
+ chunk_empty);
+ }
+ }
return TRUE;
}
@@ -391,6 +419,30 @@ static void process_payloads(private_ike_init_t *this, message_t *message)
handle_supported_hash_algorithms(this, notify);
}
break;
+ case REDIRECTED_FROM:
+ {
+ identification_t *gateway;
+ chunk_t data;
+
+ data = notify->get_notification_data(notify);
+ gateway = redirect_data_parse(data, NULL);
+ if (!gateway)
+ {
+ DBG1(DBG_IKE, "received invalid REDIRECTED_FROM "
+ "notify, ignored");
+ break;
+ }
+ DBG1(DBG_IKE, "client got redirected from %Y", gateway);
+ gateway->destroy(gateway);
+ /* fall-through */
+ }
+ case REDIRECT_SUPPORTED:
+ if (!this->old_sa)
+ {
+ this->ike_sa->enable_extension(this->ike_sa,
+ EXT_IKE_REDIRECTION);
+ }
+ break;
default:
/* other notifies are handled elsewhere */
break;
@@ -550,6 +602,8 @@ static bool derive_keys(private_ike_init_t *this,
METHOD(task_t, build_r, status_t,
private_ike_init_t *this, message_t *message)
{
+ identification_t *gateway;
+
/* check if we have everything we need */
if (this->proposal == NULL ||
this->other_nonce.len == 0 || this->my_nonce.len == 0)
@@ -560,6 +614,22 @@ METHOD(task_t, build_r, status_t,
}
this->ike_sa->set_proposal(this->ike_sa, this->proposal);
+ /* check if we'd have to redirect the client */
+ if (!this->old_sa &&
+ this->ike_sa->supports_extension(this->ike_sa, EXT_IKE_REDIRECTION) &&
+ charon->redirect->redirect_on_init(charon->redirect, this->ike_sa,
+ &gateway))
+ {
+ chunk_t data;
+
+ DBG1(DBG_IKE, "redirecting peer to %Y", gateway);
+ data = redirect_data_create(gateway, this->other_nonce);
+ message->add_notify(message, TRUE, REDIRECT, data);
+ gateway->destroy(gateway);
+ chunk_free(&data);
+ return FAILED;
+ }
+
if (this->dh == NULL ||
!this->proposal->has_dh_group(this->proposal, this->dh_group))
{
@@ -623,6 +693,54 @@ static void raise_alerts(private_ike_init_t *this, notify_type_t type)
}
}
+METHOD(task_t, pre_process_i, status_t,
+ private_ike_init_t *this, message_t *message)
+{
+ enumerator_t *enumerator;
+ payload_t *payload;
+
+ /* check for erroneous notifies */
+ enumerator = message->create_payload_enumerator(message);
+ while (enumerator->enumerate(enumerator, &payload))
+ {
+ if (payload->get_type(payload) == PLV2_NOTIFY)
+ {
+ notify_payload_t *notify = (notify_payload_t*)payload;
+ notify_type_t type = notify->get_notify_type(notify);
+
+ switch (type)
+ {
+ case REDIRECT:
+ {
+ identification_t *gateway;
+ chunk_t data, nonce = chunk_empty;
+ status_t status = SUCCESS;
+
+ if (this->old_sa)
+ {
+ break;
+ }
+ data = notify->get_notification_data(notify);
+ gateway = redirect_data_parse(data, &nonce);
+ if (!gateway || !chunk_equals(nonce, this->my_nonce))
+ {
+ DBG1(DBG_IKE, "received invalid REDIRECT notify");
+ status = FAILED;
+ }
+ DESTROY_IF(gateway);
+ chunk_free(&nonce);
+ enumerator->destroy(enumerator);
+ return status;
+ }
+ default:
+ break;
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+ return SUCCESS;
+}
+
METHOD(task_t, process_i, status_t,
private_ike_init_t *this, message_t *message)
{
@@ -678,6 +796,29 @@ METHOD(task_t, process_i, status_t,
this->retry++;
return NEED_MORE;
}
+ case REDIRECT:
+ {
+ identification_t *gateway;
+ chunk_t data, nonce = chunk_empty;
+ status_t status = FAILED;
+
+ if (this->old_sa)
+ {
+ DBG1(DBG_IKE, "received REDIRECT notify during rekeying"
+ ", ignored");
+ break;
+ }
+ data = notify->get_notification_data(notify);
+ gateway = redirect_data_parse(data, &nonce);
+ if (this->ike_sa->handle_redirect(this->ike_sa, gateway))
+ {
+ status = NEED_MORE;
+ }
+ DESTROY_IF(gateway);
+ chunk_free(&nonce);
+ enumerator->destroy(enumerator);
+ return status;
+ }
default:
{
if (type <= 16383)
@@ -802,6 +943,8 @@ ike_init_t *ike_init_create(ike_sa_t *ike_sa, bool initiator, ike_sa_t *old_sa)
.old_sa = old_sa,
.signature_authentication = lib->settings->get_bool(lib->settings,
"%s.signature_authentication", TRUE, lib->ns),
+ .follow_redirects = lib->settings->get_bool(lib->settings,
+ "%s.follow_redirects", TRUE, lib->ns),
);
this->nonceg = this->keymat->keymat.create_nonce_gen(&this->keymat->keymat);
@@ -809,6 +952,7 @@ ike_init_t *ike_init_create(ike_sa_t *ike_sa, bool initiator, ike_sa_t *old_sa)
{
this->public.task.build = _build_i;
this->public.task.process = _process_i;
+ this->public.task.pre_process = _pre_process_i;
}
else
{
diff --git a/src/libcharon/sa/ikev2/tasks/ike_me.c b/src/libcharon/sa/ikev2/tasks/ike_me.c
index a7e7505a1..10d412ffd 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_me.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_me.c
@@ -17,7 +17,6 @@
#include <string.h>
-#include <hydra.h>
#include <daemon.h>
#include <config/peer_cfg.h>
#include <encoding/payloads/id_payload.h>
@@ -135,8 +134,8 @@ static void gather_and_add_endpoints(private_ike_me_t *this, message_t *message)
host = this->ike_sa->get_my_host(this->ike_sa);
port = host->get_port(host);
- enumerator = hydra->kernel_interface->create_address_enumerator(
- hydra->kernel_interface, ADDR_TYPE_REGULAR);
+ enumerator = charon->kernel->create_address_enumerator(charon->kernel,
+ ADDR_TYPE_REGULAR);
while (enumerator->enumerate(enumerator, (void**)&addr))
{
host = addr->clone(addr);
diff --git a/src/libcharon/sa/ikev2/tasks/ike_mobike.c b/src/libcharon/sa/ikev2/tasks/ike_mobike.c
index cbdc5e797..3f7bb175f 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_mobike.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_mobike.c
@@ -18,7 +18,6 @@
#include <string.h>
-#include <hydra.h>
#include <daemon.h>
#include <sa/ikev2/tasks/ike_natd.h>
#include <encoding/payloads/notify_payload.h>
@@ -196,8 +195,8 @@ static void build_address_list(private_ike_mobike_t *this, message_t *message)
int added = 0;
me = this->ike_sa->get_my_host(this->ike_sa);
- enumerator = hydra->kernel_interface->create_address_enumerator(
- hydra->kernel_interface, ADDR_TYPE_REGULAR);
+ enumerator = charon->kernel->create_address_enumerator(charon->kernel,
+ ADDR_TYPE_REGULAR);
while (enumerator->enumerate(enumerator, (void**)&host))
{
if (me->ip_equals(me, host))
@@ -333,8 +332,7 @@ METHOD(ike_mobike_t, transmit, bool,
if (!this->check)
{
- me = hydra->kernel_interface->get_source_addr(hydra->kernel_interface,
- other_old, me_old);
+ me = charon->kernel->get_source_addr(charon->kernel, other_old, me_old);
if (me)
{
if (me->ip_equals(me, me_old))
@@ -372,8 +370,7 @@ METHOD(ike_mobike_t, transmit, bool,
{
continue;
}
- me = hydra->kernel_interface->get_source_addr(
- hydra->kernel_interface, other, NULL);
+ me = charon->kernel->get_source_addr(charon->kernel, other, NULL);
if (me)
{
/* reuse port for an active address, 4500 otherwise */
@@ -407,7 +404,7 @@ METHOD(task_t, build_i, status_t,
/* we check if the existing address is still valid */
old = message->get_source(message);
- new = hydra->kernel_interface->get_source_addr(hydra->kernel_interface,
+ new = charon->kernel->get_source_addr(charon->kernel,
message->get_destination(message), old);
if (new)
{
diff --git a/src/libcharon/sa/ikev2/tasks/ike_natd.c b/src/libcharon/sa/ikev2/tasks/ike_natd.c
index dd34c1234..4bf5264dd 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_natd.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_natd.c
@@ -18,7 +18,6 @@
#include <string.h>
-#include <hydra.h>
#include <daemon.h>
#include <config/peer_cfg.h>
#include <crypto/hashers/hasher.h>
@@ -86,7 +85,7 @@ static bool force_encap(ike_cfg_t *ike_cfg)
{
if (!ike_cfg->force_encap(ike_cfg))
{
- return hydra->kernel_interface->get_features(hydra->kernel_interface) &
+ return charon->kernel->get_features(charon->kernel) &
KERNEL_REQUIRE_UDP_ENCAPSULATION;
}
return TRUE;
@@ -327,7 +326,7 @@ METHOD(task_t, build_i, status_t,
}
else
{
- host = hydra->kernel_interface->get_source_addr(hydra->kernel_interface,
+ host = charon->kernel->get_source_addr(charon->kernel,
this->ike_sa->get_other_host(this->ike_sa), NULL);
if (host)
{ /* 2. */
@@ -341,8 +340,8 @@ METHOD(task_t, build_i, status_t,
}
else
{ /* 3. */
- enumerator = hydra->kernel_interface->create_address_enumerator(
- hydra->kernel_interface, ADDR_TYPE_REGULAR);
+ enumerator = charon->kernel->create_address_enumerator(
+ charon->kernel, ADDR_TYPE_REGULAR);
while (enumerator->enumerate(enumerator, (void**)&host))
{
/* apply port 500 to host, but work on a copy */
diff --git a/src/libcharon/sa/ikev2/tasks/ike_redirect.c b/src/libcharon/sa/ikev2/tasks/ike_redirect.c
new file mode 100644
index 000000000..f82c80f71
--- /dev/null
+++ b/src/libcharon/sa/ikev2/tasks/ike_redirect.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2015 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "ike_redirect.h"
+
+#include <daemon.h>
+#include <processing/jobs/delete_ike_sa_job.h>
+
+typedef struct private_ike_redirect_t private_ike_redirect_t;
+
+/**
+ * Private members
+ */
+struct private_ike_redirect_t {
+
+ /**
+ * Public interface
+ */
+ ike_redirect_t public;
+
+ /**
+ * Assigned IKE_SA
+ */
+ ike_sa_t *ike_sa;
+
+ /**
+ * Gateway ID to redirect to
+ */
+ identification_t *gateway;
+};
+
+METHOD(task_t, build_i, status_t,
+ private_ike_redirect_t *this, message_t *message)
+{
+ chunk_t data;
+
+ DBG1(DBG_IKE, "redirecting peer to %Y", this->gateway);
+ data = redirect_data_create(this->gateway, chunk_empty);
+ message->add_notify(message, FALSE, REDIRECT, data);
+ chunk_free(&data);
+ this->ike_sa->set_condition(this->ike_sa, COND_REDIRECTED, TRUE);
+ return NEED_MORE;
+}
+
+METHOD(task_t, process_r, status_t,
+ private_ike_redirect_t *this, message_t *message)
+{
+ notify_payload_t *notify;
+ identification_t *to;
+
+ notify = message->get_notify(message, REDIRECT);
+ if (!notify)
+ {
+ return SUCCESS;
+ }
+
+ to = redirect_data_parse(notify->get_notification_data(notify), NULL);
+ if (!to)
+ {
+ DBG1(DBG_IKE, "received invalid REDIRECT notify");
+ }
+ else
+ {
+ this->ike_sa->handle_redirect(this->ike_sa, to);
+ to->destroy(to);
+ }
+ return SUCCESS;
+}
+
+METHOD(task_t, build_r, status_t,
+ private_ike_redirect_t *this, message_t *message)
+{
+ /* not called because SUCCESS is returned above */
+ return SUCCESS;
+}
+
+METHOD(task_t, process_i, status_t,
+ private_ike_redirect_t *this, message_t *message)
+{
+ delete_ike_sa_job_t *job;
+
+ /* if the peer does not delete the SA we do so after a while */
+ job = delete_ike_sa_job_create(this->ike_sa->get_id(this->ike_sa), TRUE);
+ lib->scheduler->schedule_job(lib->scheduler, (job_t*)job,
+ lib->settings->get_int(lib->settings,
+ "%s.half_open_timeout", HALF_OPEN_IKE_SA_TIMEOUT,
+ lib->ns));
+ return SUCCESS;
+}
+
+METHOD(task_t, get_type, task_type_t,
+ private_ike_redirect_t *this)
+{
+ return TASK_IKE_REDIRECT;
+}
+
+METHOD(task_t, migrate, void,
+ private_ike_redirect_t *this, ike_sa_t *ike_sa)
+{
+ this->ike_sa = ike_sa;
+}
+
+METHOD(task_t, destroy, void,
+ private_ike_redirect_t *this)
+{
+ DESTROY_IF(this->gateway);
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+ike_redirect_t *ike_redirect_create(ike_sa_t *ike_sa, identification_t *to)
+{
+ private_ike_redirect_t *this;
+
+ INIT(this,
+ .public = {
+ .task = {
+ .get_type = _get_type,
+ .build = _build_r,
+ .process = _process_r,
+ .migrate = _migrate,
+ .destroy = _destroy,
+ },
+ },
+ .ike_sa = ike_sa,
+ );
+
+ if (to)
+ {
+ this->gateway = to->clone(to);
+ this->public.task.build = _build_i;
+ this->public.task.process = _process_i;
+ }
+
+ return &this->public;
+}
diff --git a/src/libcharon/sa/ikev2/tasks/ike_redirect.h b/src/libcharon/sa/ikev2/tasks/ike_redirect.h
new file mode 100644
index 000000000..afa00ce5d
--- /dev/null
+++ b/src/libcharon/sa/ikev2/tasks/ike_redirect.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2015 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup ike_redirect ike_redirect
+ * @{ @ingroup tasks_v2
+ */
+
+#ifndef IKE_REDIRECT_H_
+#define IKE_REDIRECT_H_
+
+typedef struct ike_redirect_t ike_redirect_t;
+
+#include <library.h>
+#include <sa/ike_sa.h>
+#include <sa/task.h>
+
+/**
+ * Task that handles redirection requests for established SAs.
+ */
+struct ike_redirect_t {
+
+ /**
+ * Implements the task_t interface
+ */
+ task_t task;
+};
+
+/**
+ * Create a new ike_redirect_t task.
+ *
+ * As initiator (i.e. original responder) pass the ID of the target gateway,
+ * as responder (i.e. original initiator) this argument is NULL.
+ *
+ * @param ike_sa IKE_SA this task works for
+ * @param to gateway ID (gets cloned), or NULL as responder
+ * @return task instance
+ */
+ike_redirect_t *ike_redirect_create(ike_sa_t *ike_sa,
+ identification_t *to);
+
+#endif /** IKE_REDIRECT_H_ @}*/
diff --git a/src/libcharon/sa/ikev2/tasks/ike_vendor.c b/src/libcharon/sa/ikev2/tasks/ike_vendor.c
index cb3c270dc..e85b276e8 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_vendor.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_vendor.c
@@ -13,6 +13,29 @@
* for more details.
*/
+/*
+ * Copyright (C) 2016 secunet Security Networks AG
+ * Copyright (C) 2016 Thomas Egerer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
#include "ike_vendor.h"
#include <daemon.h>
@@ -49,6 +72,8 @@ typedef struct {
char *desc;
/* extension flag negotiated with vendor ID, if any */
ike_extension_t extension;
+ /* Value from strongswan.conf, whether to send vendor ID */
+ char *setting;
/* length of vendor ID string, 0 for NULL terminated */
int len;
/* vendor ID string */
@@ -68,23 +93,23 @@ static chunk_t get_vid_data(vid_data_t *data)
*/
static vid_data_t vids[] = {
/* strongSwan MD5("strongSwan") */
- { "strongSwan", EXT_STRONGSWAN, 16,
+ { "strongSwan", EXT_STRONGSWAN, "send_vendor_id", 16,
"\x88\x2f\xe5\x6d\x6f\xd2\x0d\xbc\x22\x51\x61\x3b\x2e\xbe\x5b\xeb"},
- { "Cisco Delete Reason", 0, 0,
+ { "Cisco Delete Reason", 0, NULL, 0,
"CISCO-DELETE-REASON" },
- { "Cisco Copyright (c) 2009", 0, 0,
+ { "Cisco Copyright (c) 2009", 0, NULL, 0,
"CISCO(COPYRIGHT)&Copyright (c) 2009 Cisco Systems, Inc." },
- { "FRAGMENTATION", 0, 16,
+ { "FRAGMENTATION", 0, NULL, 16,
"\x40\x48\xb7\xd5\x6e\xbc\xe8\x85\x25\xe7\xde\x7f\x00\xd6\xc2\xd3"},
- { "MS NT5 ISAKMPOAKLEY v7", 0, 20,
+ { "MS NT5 ISAKMPOAKLEY v7", 0, NULL, 20,
"\x1e\x2b\x51\x69\x05\x99\x1c\x7d\x7c\x96\xfc\xbf\xb5\x87\xe4\x61\x00\x00\x00\x07"},
- { "MS NT5 ISAKMPOAKLEY v8", 0, 20,
+ { "MS NT5 ISAKMPOAKLEY v8", 0, NULL, 20,
"\x1e\x2b\x51\x69\x05\x99\x1c\x7d\x7c\x96\xfc\xbf\xb5\x87\xe4\x61\x00\x00\x00\x08"},
- { "MS NT5 ISAKMPOAKLEY v9", 0, 20,
+ { "MS NT5 ISAKMPOAKLEY v9", 0, NULL, 20,
"\x1e\x2b\x51\x69\x05\x99\x1c\x7d\x7c\x96\xfc\xbf\xb5\x87\xe4\x61\x00\x00\x00\x09"},
- { "MS-Negotiation Discovery Capable", 0, 16,
+ { "MS-Negotiation Discovery Capable", 0, NULL, 16,
"\xfb\x1d\xe3\xcd\xf3\x41\xb7\xea\x16\xb7\xe5\xbe\x08\x55\xf1\x20"},
- { "Vid-Initial-Contact", 0, 16,
+ { "Vid-Initial-Contact", 0, NULL, 16,
"\x26\x24\x4d\x38\xed\xdb\x61\xb3\x17\x2a\x36\xe3\xd0\xcf\xb8\x19"},
};
@@ -92,14 +117,19 @@ METHOD(task_t, build, status_t,
private_ike_vendor_t *this, message_t *message)
{
vendor_id_payload_t *vid;
- bool strongswan;
+ bool send_vid;
int i;
- strongswan = lib->settings->get_bool(lib->settings,
- "%s.send_vendor_id", FALSE, lib->ns);
for (i = 0; i < countof(vids); i++)
{
- if (vids[i].extension == EXT_STRONGSWAN && strongswan)
+ send_vid = FALSE;
+
+ if (vids[i].setting)
+ {
+ send_vid = lib->settings->get_bool(lib->settings, "%s.%s", send_vid,
+ lib->ns, vids[i].setting);
+ }
+ if (send_vid)
{
DBG2(DBG_IKE, "sending %s vendor ID", vids[i].desc);
vid = vendor_id_payload_create_data(PLV2_VENDOR_ID,
diff --git a/src/libcharon/sa/ikev2/tasks/ike_verify_peer_cert.c b/src/libcharon/sa/ikev2/tasks/ike_verify_peer_cert.c
new file mode 100644
index 000000000..069d51d00
--- /dev/null
+++ b/src/libcharon/sa/ikev2/tasks/ike_verify_peer_cert.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2015 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "ike_verify_peer_cert.h"
+
+#include <daemon.h>
+#include <sa/ikev2/tasks/ike_delete.h>
+
+typedef struct private_ike_verify_peer_cert_t private_ike_verify_peer_cert_t;
+
+/**
+ * Private members
+ */
+struct private_ike_verify_peer_cert_t {
+
+ /**
+ * Public methods and task_t interface.
+ */
+ ike_verify_peer_cert_t public;
+
+ /**
+ * Assigned IKE_SA.
+ */
+ ike_sa_t *ike_sa;
+
+ /**
+ * Child ike_delete task, if necessary
+ */
+ ike_delete_t *ike_delete;
+};
+
+METHOD(task_t, build_i, status_t,
+ private_ike_verify_peer_cert_t *this, message_t *message)
+{
+ if (!this->ike_sa->verify_peer_certificate(this->ike_sa))
+ {
+ DBG1(DBG_IKE, "peer certificate verification failed, deleting SA");
+ this->ike_delete = ike_delete_create(this->ike_sa, TRUE);
+ return this->ike_delete->task.build(&this->ike_delete->task, message);
+ }
+ DBG1(DBG_IKE, "peer certificate successfully verified");
+ message->set_exchange_type(message, EXCHANGE_TYPE_UNDEFINED);
+ return SUCCESS;
+}
+
+METHOD(task_t, process_i, status_t,
+ private_ike_verify_peer_cert_t *this, message_t *message)
+{
+ if (this->ike_delete)
+ {
+ this->ike_delete->task.process(&this->ike_delete->task, message);
+ /* try to reestablish the IKE_SA and all children */
+ this->ike_sa->reestablish(this->ike_sa);
+ }
+ return DESTROY_ME;
+}
+
+METHOD(task_t, get_type, task_type_t,
+ private_ike_verify_peer_cert_t *this)
+{
+ return TASK_IKE_VERIFY_PEER_CERT;
+}
+
+METHOD(task_t, migrate, void,
+ private_ike_verify_peer_cert_t *this, ike_sa_t *ike_sa)
+{
+ if (this->ike_delete)
+ {
+ this->ike_delete->task.migrate(&this->ike_delete->task, ike_sa);
+ }
+ this->ike_sa = ike_sa;
+}
+
+METHOD(task_t, destroy, void,
+ private_ike_verify_peer_cert_t *this)
+{
+ if (this->ike_delete)
+ {
+ this->ike_delete->task.destroy(&this->ike_delete->task);
+ }
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+ike_verify_peer_cert_t *ike_verify_peer_cert_create(ike_sa_t *ike_sa)
+{
+ private_ike_verify_peer_cert_t *this;
+
+ INIT(this,
+ .public = {
+ .task = {
+ .get_type = _get_type,
+ .migrate = _migrate,
+ .build = _build_i,
+ .process = _process_i,
+ .destroy = _destroy,
+ },
+ },
+ .ike_sa = ike_sa,
+ );
+
+ return &this->public;
+}
diff --git a/src/libcharon/sa/ikev2/tasks/ike_verify_peer_cert.h b/src/libcharon/sa/ikev2/tasks/ike_verify_peer_cert.h
new file mode 100644
index 000000000..3d9aae0b3
--- /dev/null
+++ b/src/libcharon/sa/ikev2/tasks/ike_verify_peer_cert.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2015 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup ike_verify_peer_cert ike_verify_peer_cert
+ * @{ @ingroup tasks_v2
+ */
+
+#ifndef IKE_VERIFY_PEER_CERT_H_
+#define IKE_VERIFY_PEER_CERT_H_
+
+typedef struct ike_verify_peer_cert_t ike_verify_peer_cert_t;
+
+#include <library.h>
+#include <sa/ike_sa.h>
+#include <sa/task.h>
+
+/**
+ * Task of type ike_verify_peer_cert, verifies a peer's certificate.
+ *
+ * This task (re-)verifies the peer's certificate explicitly including online
+ * OCSP and CRL checks.
+ */
+struct ike_verify_peer_cert_t {
+
+ /**
+ * Implements the task_t interface
+ */
+ task_t task;
+};
+
+/**
+ * Create a new ike_verify_peer_cert task.
+ *
+ * This task is initiator only.
+ *
+ * @param ike_sa IKE_SA this task works for
+ * @return ike_verify_peer_cert task to handle by the task_manager
+ */
+ike_verify_peer_cert_t *ike_verify_peer_cert_create(ike_sa_t *ike_sa);
+
+#endif /** IKE_VERIFY_PEER_CERT_H_ @}*/