aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Brunner <tobias@strongswan.org>2016-03-10 11:48:12 +0100
committerTobias Brunner <tobias@strongswan.org>2016-03-10 11:50:57 +0100
commitf893b47e3d854f4051b8d1549cdc0d6d661aa235 (patch)
tree9d3cf491012ee2cce5426c219e9f07d187316f3f
parent819da83fccf99acf7af1ed2bf61a498425c375e1 (diff)
parentb4337c5b027871d6bb076b85d9a8699f86a74fa6 (diff)
downloadstrongswan-f893b47e3d854f4051b8d1549cdc0d6d661aa235.tar.bz2
strongswan-f893b47e3d854f4051b8d1549cdc0d6d661aa235.tar.xz
Merge branch 'mbb-reauth-online-revocation'
With these changes initiators of make-before-break reauthentications suspend online revocation checks until after the new IKE_SA and all CHILD_SAs are established. See f1cbacc5d1be for details why that's necessary.
-rw-r--r--NEWS9
-rw-r--r--src/libcharon/Android.mk3
-rw-r--r--src/libcharon/Makefile.am3
-rw-r--r--src/libcharon/sa/ike_sa.c120
-rw-r--r--src/libcharon/sa/ike_sa.h13
-rw-r--r--src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.c2
-rw-r--r--src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c9
-rw-r--r--src/libcharon/sa/ikev2/task_manager_v2.c12
-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
-rw-r--r--src/libcharon/sa/task.c1
-rw-r--r--src/libcharon/sa/task.h2
-rw-r--r--src/libstrongswan/credentials/auth_cfg.c16
-rw-r--r--src/libstrongswan/credentials/auth_cfg.h2
-rw-r--r--src/libstrongswan/credentials/credential_manager.c8
-rw-r--r--src/libstrongswan/credentials/credential_manager.h7
-rw-r--r--src/libtls/tls_peer.c3
-rw-r--r--src/libtls/tls_server.c2
-rwxr-xr-xtesting/hosts/winnetou/etc/openssl/generate-crl3
-rw-r--r--testing/tests/ikev2/reauth-mbb-revoked/description.txt15
-rw-r--r--testing/tests/ikev2/reauth-mbb-revoked/evaltest.dat10
-rw-r--r--testing/tests/ikev2/reauth-mbb-revoked/hosts/carol/etc/ipsec.conf21
-rw-r--r--testing/tests/ikev2/reauth-mbb-revoked/hosts/carol/etc/strongswan.conf7
-rw-r--r--testing/tests/ikev2/reauth-mbb-revoked/hosts/moon/etc/ipsec.conf19
-rw-r--r--testing/tests/ikev2/reauth-mbb-revoked/hosts/moon/etc/strongswan.conf5
-rw-r--r--testing/tests/ikev2/reauth-mbb-revoked/posttest.dat3
-rw-r--r--testing/tests/ikev2/reauth-mbb-revoked/pretest.dat4
-rw-r--r--testing/tests/ikev2/reauth-mbb-revoked/test.conf21
28 files changed, 477 insertions, 14 deletions
diff --git a/NEWS b/NEWS
index fcb89f09e..1d69cd822 100644
--- a/NEWS
+++ b/NEWS
@@ -11,6 +11,15 @@ strongswan-5.4.0
constraints against IKEv2 authentication in rightauth, which allows the use
of different signature schemes for trustchain verification and authentication.
+- The initiator of an IKEv2 make-before-break reauthentication now suspends
+ online certificate revocation checks (OCSP, CRLs) until the new IKE_SA and all
+ CHILD_SAs are established. This is required if the checks are done over the
+ CHILD_SA established with the new IKE_SA. This is not possible until the
+ initiator installs this SA and that only happens after the authentication is
+ completed successfully. So we suspend the checks during the reauthentication
+ and do them afterwards, if they fail the IKE_SA is closed. This change has no
+ effect on the behavior during the authentication of the initial IKE_SA.
+
- For the vici plugin a Vici:Session Perl CPAN module has been added to allow
Perl applications to control and/or monitor the IKE daemon using the VICI
interface, similar to the existing Python egg or Ruby gem.
diff --git a/src/libcharon/Android.mk b/src/libcharon/Android.mk
index 0b09d100d..8f8c96588 100644
--- a/src/libcharon/Android.mk
+++ b/src/libcharon/Android.mk
@@ -111,7 +111,8 @@ sa/ikev2/tasks/ike_reauth.c sa/ikev2/tasks/ike_reauth.h \
sa/ikev2/tasks/ike_reauth_complete.c sa/ikev2/tasks/ike_reauth_complete.h \
sa/ikev2/tasks/ike_redirect.c sa/ikev2/tasks/ike_redirect.h \
sa/ikev2/tasks/ike_auth_lifetime.c sa/ikev2/tasks/ike_auth_lifetime.h \
-sa/ikev2/tasks/ike_vendor.c sa/ikev2/tasks/ike_vendor.h
+sa/ikev2/tasks/ike_vendor.c sa/ikev2/tasks/ike_vendor.h \
+sa/ikev2/tasks/ike_verify_peer_cert.c sa/ikev2/tasks/ike_verify_peer_cert.h
libcharon_la_SOURCES += \
sa/ikev1/keymat_v1.c sa/ikev1/keymat_v1.h \
diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am
index 062b96aff..61e57c1cb 100644
--- a/src/libcharon/Makefile.am
+++ b/src/libcharon/Makefile.am
@@ -111,7 +111,8 @@ sa/ikev2/tasks/ike_reauth.c sa/ikev2/tasks/ike_reauth.h \
sa/ikev2/tasks/ike_reauth_complete.c sa/ikev2/tasks/ike_reauth_complete.h \
sa/ikev2/tasks/ike_redirect.c sa/ikev2/tasks/ike_redirect.h \
sa/ikev2/tasks/ike_auth_lifetime.c sa/ikev2/tasks/ike_auth_lifetime.h \
-sa/ikev2/tasks/ike_vendor.c sa/ikev2/tasks/ike_vendor.h
+sa/ikev2/tasks/ike_vendor.c sa/ikev2/tasks/ike_vendor.h \
+sa/ikev2/tasks/ike_verify_peer_cert.c sa/ikev2/tasks/ike_verify_peer_cert.h
endif
if USE_IKEV1
diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c
index b07ff0e74..bcbff3211 100644
--- a/src/libcharon/sa/ike_sa.c
+++ b/src/libcharon/sa/ike_sa.c
@@ -58,6 +58,7 @@
#include <sa/ikev2/tasks/ike_auth_lifetime.h>
#include <sa/ikev2/tasks/ike_reauth_complete.h>
#include <sa/ikev2/tasks/ike_redirect.h>
+#include <credentials/sets/auth_cfg_wrapper.h>
#ifdef ME
#include <sa/ikev2/tasks/ike_me.h>
@@ -482,6 +483,113 @@ static void flush_auth_cfgs(private_ike_sa_t *this)
}
}
+METHOD(ike_sa_t, verify_peer_certificate, bool,
+ private_ike_sa_t *this)
+{
+ enumerator_t *e1, *e2, *certs;
+ auth_cfg_t *cfg, *cfg_done;
+ certificate_t *peer, *cert;
+ public_key_t *key;
+ auth_cfg_t *auth;
+ auth_cfg_wrapper_t *wrapper;
+ time_t not_before, not_after;
+ bool valid = TRUE, found;
+
+ if (this->state != IKE_ESTABLISHED)
+ {
+ DBG1(DBG_IKE, "unable to verify peer certificate in state %N",
+ ike_sa_state_names, this->state);
+ return FALSE;
+ }
+
+ if (!this->flush_auth_cfg &&
+ lib->settings->get_bool(lib->settings,
+ "%s.flush_auth_cfg", FALSE, lib->ns))
+ { /* we can do this check only once if auth configs are flushed */
+ DBG1(DBG_IKE, "unable to verify peer certificate as authentication "
+ "information has been flushed");
+ return FALSE;
+ }
+ this->public.set_condition(&this->public, COND_ONLINE_VALIDATION_SUSPENDED,
+ FALSE);
+
+ e1 = this->peer_cfg->create_auth_cfg_enumerator(this->peer_cfg, FALSE);
+ e2 = array_create_enumerator(this->other_auths);
+ while (e1->enumerate(e1, &cfg))
+ {
+ if (!e2->enumerate(e2, &cfg_done))
+ { /* this should not happen as the authentication should never have
+ * succeeded */
+ valid = FALSE;
+ break;
+ }
+ if ((uintptr_t)cfg_done->get(cfg_done,
+ AUTH_RULE_AUTH_CLASS) != AUTH_CLASS_PUBKEY)
+ {
+ continue;
+ }
+ peer = cfg_done->get(cfg_done, AUTH_RULE_SUBJECT_CERT);
+ if (!peer)
+ {
+ DBG1(DBG_IKE, "no subject certificate found, skipping certificate "
+ "verification");
+ continue;
+ }
+ if (!peer->get_validity(peer, NULL, &not_before, &not_after))
+ {
+ DBG1(DBG_IKE, "peer certificate invalid (valid from %T to %T)",
+ &not_before, FALSE, &not_after, FALSE);
+ valid = FALSE;
+ break;
+ }
+ key = peer->get_public_key(peer);
+ if (!key)
+ {
+ DBG1(DBG_IKE, "unable to retrieve public key, skipping certificate "
+ "verification");
+ continue;
+ }
+ DBG1(DBG_IKE, "verifying peer certificate");
+ /* serve received certificates */
+ wrapper = auth_cfg_wrapper_create(cfg_done);
+ lib->credmgr->add_local_set(lib->credmgr, &wrapper->set, FALSE);
+ certs = lib->credmgr->create_trusted_enumerator(lib->credmgr,
+ key->get_type(key), peer->get_subject(peer), TRUE);
+ key->destroy(key);
+
+ found = FALSE;
+ while (certs->enumerate(certs, &cert, &auth))
+ {
+ if (peer->equals(peer, cert))
+ {
+ cfg_done->add(cfg_done, AUTH_RULE_CERT_VALIDATION_SUSPENDED,
+ FALSE);
+ cfg_done->merge(cfg_done, auth, FALSE);
+ valid = cfg_done->complies(cfg_done, cfg, TRUE);
+ found = TRUE;
+ break;
+ }
+ }
+ certs->destroy(certs);
+ lib->credmgr->remove_local_set(lib->credmgr, &wrapper->set);
+ wrapper->destroy(wrapper);
+ if (!found || !valid)
+ {
+ valid = FALSE;
+ break;
+ }
+ }
+ e1->destroy(e1);
+ e2->destroy(e2);
+
+ if (this->flush_auth_cfg)
+ {
+ this->flush_auth_cfg = FALSE;
+ flush_auth_cfgs(this);
+ }
+ return valid;
+}
+
METHOD(ike_sa_t, get_proposal, proposal_t*,
private_ike_sa_t *this)
{
@@ -1441,9 +1549,14 @@ METHOD(ike_sa_t, process_message, status_t,
status = this->task_manager->process_message(this->task_manager, message);
if (this->flush_auth_cfg && this->state == IKE_ESTABLISHED)
{
- /* authentication completed */
- this->flush_auth_cfg = FALSE;
- flush_auth_cfgs(this);
+ /* authentication completed but if the online validation is suspended we
+ * need the auth cfgs until we did the delayed verification, we flush
+ * them afterwards */
+ if (!has_condition(this, COND_ONLINE_VALIDATION_SUSPENDED))
+ {
+ this->flush_auth_cfg = FALSE;
+ flush_auth_cfgs(this);
+ }
}
return status;
}
@@ -2750,6 +2863,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator,
.set_peer_cfg = _set_peer_cfg,
.get_auth_cfg = _get_auth_cfg,
.create_auth_cfg_enumerator = _create_auth_cfg_enumerator,
+ .verify_peer_certificate = _verify_peer_certificate,
.add_auth_cfg = _add_auth_cfg,
.get_proposal = _get_proposal,
.set_proposal = _set_proposal,
diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h
index 158a690df..836360e3c 100644
--- a/src/libcharon/sa/ike_sa.h
+++ b/src/libcharon/sa/ike_sa.h
@@ -217,6 +217,11 @@ enum ike_condition_t {
* This IKE_SA has been redirected
*/
COND_REDIRECTED = (1<<11),
+
+ /**
+ * Online certificate revocation checking is suspended for this IKE_SA
+ */
+ COND_ONLINE_VALIDATION_SUSPENDED = (1<<12),
};
/**
@@ -522,6 +527,14 @@ struct ike_sa_t {
enumerator_t* (*create_auth_cfg_enumerator)(ike_sa_t *this, bool local);
/**
+ * Verify the trustchains (validity, revocation) in completed public key
+ * auth rounds.
+ *
+ * @return TRUE if certificates were valid, FALSE otherwise
+ */
+ bool (*verify_peer_certificate)(ike_sa_t *this);
+
+ /**
* Get the selected proposal of this IKE_SA.
*
* @return selected proposal
diff --git a/src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.c b/src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.c
index 793e6d5c1..eee7dd10b 100644
--- a/src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.c
+++ b/src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.c
@@ -173,7 +173,7 @@ METHOD(authenticator_t, process, status_t,
sig = sig_payload->get_hash(sig_payload);
auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
enumerator = lib->credmgr->create_public_enumerator(lib->credmgr, this->type,
- id, auth);
+ id, auth, TRUE);
while (enumerator->enumerate(enumerator, &public, &current_auth))
{
if (public->verify(public, scheme, hash, sig))
diff --git a/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c b/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c
index 110c50973..04ccd4f4f 100644
--- a/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c
+++ b/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c
@@ -365,6 +365,7 @@ METHOD(authenticator_t, process, status_t,
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)
@@ -408,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,6 +424,10 @@ METHOD(authenticator_t, process, status_t,
auth->merge(auth, current_auth, FALSE);
auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
auth->add(auth, AUTH_RULE_IKE_SIGNATURE_SCHEME, (uintptr_t)scheme);
+ if (!online)
+ {
+ auth->add(auth, AUTH_RULE_CERT_VALIDATION_SUSPENDED, TRUE);
+ }
break;
}
else
diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c
index 8ed86302b..c2f972ab1 100644
--- a/src/libcharon/sa/ikev2/task_manager_v2.c
+++ b/src/libcharon/sa/ikev2/task_manager_v2.c
@@ -35,6 +35,7 @@
#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>
@@ -527,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))
{
@@ -624,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))
@@ -1650,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/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_ @}*/
diff --git a/src/libcharon/sa/task.c b/src/libcharon/sa/task.c
index 4bd2ba221..405eda66b 100644
--- a/src/libcharon/sa/task.c
+++ b/src/libcharon/sa/task.c
@@ -29,6 +29,7 @@ ENUM(task_type_names, TASK_IKE_INIT, TASK_ISAKMP_CERT_POST,
"IKE_REAUTH",
"IKE_REAUTH_COMPLETE",
"IKE_REDIRECT",
+ "IKE_VERIFY_PEER_CERT",
"IKE_DELETE",
"IKE_DPD",
"IKE_VENDOR",
diff --git a/src/libcharon/sa/task.h b/src/libcharon/sa/task.h
index b2e9d8886..31d70fb3b 100644
--- a/src/libcharon/sa/task.h
+++ b/src/libcharon/sa/task.h
@@ -59,6 +59,8 @@ enum task_type_t {
TASK_IKE_REAUTH_COMPLETE,
/** redirect an active IKE_SA */
TASK_IKE_REDIRECT,
+ /** verify a peer's certificate */
+ TASK_IKE_VERIFY_PEER_CERT,
/** delete an IKE_SA */
TASK_IKE_DELETE,
/** liveness check */
diff --git a/src/libstrongswan/credentials/auth_cfg.c b/src/libstrongswan/credentials/auth_cfg.c
index 5466a2e08..956ce08c9 100644
--- a/src/libstrongswan/credentials/auth_cfg.c
+++ b/src/libstrongswan/credentials/auth_cfg.c
@@ -46,6 +46,7 @@ ENUM(auth_rule_names, AUTH_RULE_IDENTITY, AUTH_HELPER_AC_CERT,
"RULE_SUBJECT_CERT",
"RULE_CRL_VALIDATION",
"RULE_OCSP_VALIDATION",
+ "RULE_CERT_VALIDATION_SUSPENDED",
"RULE_GROUP",
"RULE_RSA_STRENGTH",
"RULE_ECDSA_STRENGTH",
@@ -80,6 +81,7 @@ static inline bool is_multi_value_rule(auth_rule_t type)
case AUTH_RULE_AAA_IDENTITY:
case AUTH_RULE_XAUTH_IDENTITY:
case AUTH_RULE_XAUTH_BACKEND:
+ case AUTH_RULE_CERT_VALIDATION_SUSPENDED:
case AUTH_HELPER_SUBJECT_CERT:
case AUTH_HELPER_SUBJECT_HASH_URL:
case AUTH_RULE_MAX:
@@ -214,6 +216,7 @@ static void init_entry(entry_t *this, auth_rule_t type, va_list args)
case AUTH_RULE_BLISS_STRENGTH:
case AUTH_RULE_SIGNATURE_SCHEME:
case AUTH_RULE_IKE_SIGNATURE_SCHEME:
+ case AUTH_RULE_CERT_VALIDATION_SUSPENDED:
/* integer type */
this->value = (void*)(uintptr_t)va_arg(args, u_int);
break;
@@ -264,6 +267,7 @@ static bool entry_equals(entry_t *e1, entry_t *e2)
case AUTH_RULE_BLISS_STRENGTH:
case AUTH_RULE_SIGNATURE_SCHEME:
case AUTH_RULE_IKE_SIGNATURE_SCHEME:
+ case AUTH_RULE_CERT_VALIDATION_SUSPENDED:
{
return e1->value == e2->value;
}
@@ -356,6 +360,7 @@ static void destroy_entry_value(entry_t *entry)
case AUTH_RULE_BLISS_STRENGTH:
case AUTH_RULE_SIGNATURE_SCHEME:
case AUTH_RULE_IKE_SIGNATURE_SCHEME:
+ case AUTH_RULE_CERT_VALIDATION_SUSPENDED:
case AUTH_RULE_MAX:
break;
}
@@ -389,6 +394,7 @@ static void replace(private_auth_cfg_t *this, entry_enumerator_t *enumerator,
case AUTH_RULE_BLISS_STRENGTH:
case AUTH_RULE_SIGNATURE_SCHEME:
case AUTH_RULE_IKE_SIGNATURE_SCHEME:
+ case AUTH_RULE_CERT_VALIDATION_SUSPENDED:
/* integer type */
entry->value = (void*)(uintptr_t)va_arg(args, u_int);
break;
@@ -471,6 +477,7 @@ METHOD(auth_cfg_t, get, void*,
case AUTH_RULE_OCSP_VALIDATION:
return (void*)VALIDATION_FAILED;
case AUTH_RULE_IDENTITY_LOOSE:
+ case AUTH_RULE_CERT_VALIDATION_SUSPENDED:
return (void*)FALSE;
case AUTH_RULE_IDENTITY:
case AUTH_RULE_EAP_IDENTITY:
@@ -757,6 +764,11 @@ METHOD(auth_cfg_t, complies, bool,
{
uintptr_t validated;
+ if (get(this, AUTH_RULE_CERT_VALIDATION_SUSPENDED))
+ { /* skip validation, may happen later */
+ break;
+ }
+
e2 = create_enumerator(this);
while (e2->enumerate(e2, &t2, &validated))
{
@@ -934,6 +946,8 @@ METHOD(auth_cfg_t, complies, bool,
/* just an indication when verifying AUTH_RULE_IDENTITY */
case AUTH_RULE_XAUTH_BACKEND:
/* not enforced, just a hint for local authentication */
+ case AUTH_RULE_CERT_VALIDATION_SUSPENDED:
+ /* not a constraint */
case AUTH_HELPER_IM_CERT:
case AUTH_HELPER_SUBJECT_CERT:
case AUTH_HELPER_IM_HASH_URL:
@@ -1086,6 +1100,7 @@ static void merge(private_auth_cfg_t *this, private_auth_cfg_t *other, bool copy
case AUTH_RULE_BLISS_STRENGTH:
case AUTH_RULE_SIGNATURE_SCHEME:
case AUTH_RULE_IKE_SIGNATURE_SCHEME:
+ case AUTH_RULE_CERT_VALIDATION_SUSPENDED:
{
add(this, type, (uintptr_t)value);
break;
@@ -1257,6 +1272,7 @@ METHOD(auth_cfg_t, clone_, auth_cfg_t*,
case AUTH_RULE_BLISS_STRENGTH:
case AUTH_RULE_SIGNATURE_SCHEME:
case AUTH_RULE_IKE_SIGNATURE_SCHEME:
+ case AUTH_RULE_CERT_VALIDATION_SUSPENDED:
clone->add(clone, type, (uintptr_t)value);
break;
case AUTH_RULE_MAX:
diff --git a/src/libstrongswan/credentials/auth_cfg.h b/src/libstrongswan/credentials/auth_cfg.h
index 75bc7e97b..6940069de 100644
--- a/src/libstrongswan/credentials/auth_cfg.h
+++ b/src/libstrongswan/credentials/auth_cfg.h
@@ -94,6 +94,8 @@ enum auth_rule_t {
AUTH_RULE_CRL_VALIDATION,
/** result of a OCSP validation, cert_validation_t */
AUTH_RULE_OCSP_VALIDATION,
+ /** CRL/OCSP validation is disabled, bool */
+ AUTH_RULE_CERT_VALIDATION_SUSPENDED,
/** subject is member of a group, identification_t*
* The group membership constraint is fulfilled if the subject is member of
* one group defined in the constraints. */
diff --git a/src/libstrongswan/credentials/credential_manager.c b/src/libstrongswan/credentials/credential_manager.c
index 371e6404d..95c5cd777 100644
--- a/src/libstrongswan/credentials/credential_manager.c
+++ b/src/libstrongswan/credentials/credential_manager.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2015 Tobias Brunner
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -917,6 +918,8 @@ METHOD(enumerator_t, trusted_destroy, void,
DESTROY_IF(this->auth);
DESTROY_IF(this->candidates);
this->failed->destroy_offset(this->failed, offsetof(certificate_t, destroy));
+ /* check for delayed certificate cache queue */
+ cache_queue(this->this);
free(this);
}
@@ -985,7 +988,6 @@ METHOD(enumerator_t, public_destroy, void,
this->wrapper->destroy(this->wrapper);
}
this->this->lock->unlock(this->this->lock);
-
/* check for delayed certificate cache queue */
cache_queue(this->this);
free(this);
@@ -993,7 +995,7 @@ METHOD(enumerator_t, public_destroy, void,
METHOD(credential_manager_t, create_public_enumerator, enumerator_t*,
private_credential_manager_t *this, key_type_t type, identification_t *id,
- auth_cfg_t *auth)
+ auth_cfg_t *auth, bool online)
{
public_enumerator_t *enumerator;
@@ -1002,7 +1004,7 @@ METHOD(credential_manager_t, create_public_enumerator, enumerator_t*,
.enumerate = (void*)_public_enumerate,
.destroy = _public_destroy,
},
- .inner = create_trusted_enumerator(this, type, id, TRUE),
+ .inner = create_trusted_enumerator(this, type, id, online),
.this = this,
);
if (auth)
diff --git a/src/libstrongswan/credentials/credential_manager.h b/src/libstrongswan/credentials/credential_manager.h
index 445ea3f9c..022ca566c 100644
--- a/src/libstrongswan/credentials/credential_manager.h
+++ b/src/libstrongswan/credentials/credential_manager.h
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2015 Tobias Brunner
* Copyright (C) 2007-2009 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -202,14 +203,18 @@ struct credential_manager_t {
* where the auth config helper contains rules for constraint checks.
* This function is very similar to create_trusted_enumerator(), but
* gets public keys directly.
+ * If online is set, revocations are checked online for the whole
+ * trustchain.
*
* @param type type of the key to get
* @param id owner of the key, signer of the signature
* @param auth authentication infos
+ * @param online whether revocations should be checked online
* @return enumerator
*/
enumerator_t* (*create_public_enumerator)(credential_manager_t *this,
- key_type_t type, identification_t *id, auth_cfg_t *auth);
+ key_type_t type, identification_t *id, auth_cfg_t *auth,
+ bool online);
/**
* Cache a certificate by invoking cache_cert() on all registered sets.
diff --git a/src/libtls/tls_peer.c b/src/libtls/tls_peer.c
index 000dda43b..8087e2e2d 100644
--- a/src/libtls/tls_peer.c
+++ b/src/libtls/tls_peer.c
@@ -320,7 +320,8 @@ static public_key_t *find_public_key(private_tls_peer_t *this)
if (cert)
{
enumerator = lib->credmgr->create_public_enumerator(lib->credmgr,
- KEY_ANY, cert->get_subject(cert), this->server_auth);
+ KEY_ANY, cert->get_subject(cert),
+ this->server_auth, TRUE);
while (enumerator->enumerate(enumerator, &current, &auth))
{
found = auth->get(auth, AUTH_RULE_SUBJECT_CERT);
diff --git a/src/libtls/tls_server.c b/src/libtls/tls_server.c
index f9295a160..cfbe02037 100644
--- a/src/libtls/tls_server.c
+++ b/src/libtls/tls_server.c
@@ -548,7 +548,7 @@ static status_t process_cert_verify(private_tls_server_t *this,
bio_reader_t *sig;
enumerator = lib->credmgr->create_public_enumerator(lib->credmgr,
- KEY_ANY, this->peer, this->peer_auth);
+ KEY_ANY, this->peer, this->peer_auth, TRUE);
while (enumerator->enumerate(enumerator, &public, &auth))
{
sig = bio_reader_create(reader->peek(reader));
diff --git a/testing/hosts/winnetou/etc/openssl/generate-crl b/testing/hosts/winnetou/etc/openssl/generate-crl
index 842c3a1b2..de3c13dcf 100755
--- a/testing/hosts/winnetou/etc/openssl/generate-crl
+++ b/testing/hosts/winnetou/etc/openssl/generate-crl
@@ -24,6 +24,9 @@ openssl crl -in crl.pem -outform der -out strongswan.crl
cp strongswan.crl ${ROOT}
cp strongswanCert.pem ${ROOT}
cp index.html ${ROOT}
+# revoke moon's current CERT
+pki --signcrl --cacert strongswanCert.pem --cakey strongswanKey.pem --lifetime 30 --reason key-compromise --cert newcerts/2B.pem --lastcrl strongswan.crl > strongswan_moon_revoked.crl
+cp strongswan_moon_revoked.crl ${ROOT}
cd /etc/openssl/research
openssl ca -gencrl -crldays 15 -config /etc/openssl/research/openssl.cnf -out crl.pem
openssl crl -in crl.pem -outform der -out research.crl
diff --git a/testing/tests/ikev2/reauth-mbb-revoked/description.txt b/testing/tests/ikev2/reauth-mbb-revoked/description.txt
new file mode 100644
index 000000000..4e27a0b82
--- /dev/null
+++ b/testing/tests/ikev2/reauth-mbb-revoked/description.txt
@@ -0,0 +1,15 @@
+This scenario tests <b>make-before-break reauthentication</b> using overlapping
+IKE_SAs by setting the <i>make_before_break</i> strongswan.conf option. The
+initiator <b>carol</b> reauthenticates the IKE_SA with host <b>moon</b> using
+<b>ikelifetime=10s</b>, but does not close the old IKE_SA before the replacement
+CHILD_SA is in place. A constant ping from <b>carol</b> to client <b>alice</b>
+hiding in the subnet behind <b>moon</b> tests if the CHILD_SA works during the
+whole procedure.
+<p/>
+Because the responder is always able to install CHILD_SAs before the initiator
+is, some traffic sent by the responder over such a CHILD_SA might get dropped by
+the initiator (until it also installed the CHILD_SA). This is particularly
+problematic if OCSP/CRL checks are delayed or if they can also be done via the
+IPsec tunnel once it's established. Therefore, online OCSP/CRL checks are
+suspended during the reauthentication and done afterwards. This is verified here
+by revoking the responder's certificate after the SA got initially established.
diff --git a/testing/tests/ikev2/reauth-mbb-revoked/evaltest.dat b/testing/tests/ikev2/reauth-mbb-revoked/evaltest.dat
new file mode 100644
index 000000000..8fe9a2360
--- /dev/null
+++ b/testing/tests/ikev2/reauth-mbb-revoked/evaltest.dat
@@ -0,0 +1,10 @@
+winnetou::cp /var/www/strongswan.crl /var/www/strongswan.crl.bak
+winnetou::cp /var/www/strongswan_moon_revoked.crl /var/www/strongswan.crl
+carol::ipsec purgecrls
+moon:: ipsec status 2> /dev/null::rw\[1]: ESTABLISHED.*moon.strongswan.org.*carol@strongswan.org::YES
+carol::ipsec status 2> /dev/null::home\[1]: ESTABLISHED.*carol@strongswan.org.*moon.strongswan.org::YES
+carol::sleep 6
+carol::cat /var/log/daemon.log::certificate was revoked.*key compromise::YES
+carol::cat /var/log/daemon.log::peer certificate verification failed, deleting SA::YES
+moon:: ipsec status 2> /dev/null::rw\[2]: ESTABLISHED.*moon.strongswan.org.*carol@strongswan.org::NO
+carol::ipsec status 2> /dev/null::home\[2]: ESTABLISHED.*carol@strongswan.org.*moon.strongswan.org::NO
diff --git a/testing/tests/ikev2/reauth-mbb-revoked/hosts/carol/etc/ipsec.conf b/testing/tests/ikev2/reauth-mbb-revoked/hosts/carol/etc/ipsec.conf
new file mode 100644
index 000000000..ec2b41d29
--- /dev/null
+++ b/testing/tests/ikev2/reauth-mbb-revoked/hosts/carol/etc/ipsec.conf
@@ -0,0 +1,21 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+config setup
+ strictcrlpolicy=yes
+
+conn %default
+ keylife=20m
+ ikelifetime=10s
+ rekeymargin=5s
+ rekeyfuzz=0%
+ keyingtries=1
+
+conn home
+ left=PH_IP_CAROL
+ leftcert=carolCert.pem
+ leftid=carol@strongswan.org
+ right=PH_IP_MOON
+ rightid=@moon.strongswan.org
+ rightsubnet=10.1.0.0/16
+ keyexchange=ikev2
+ auto=add
diff --git a/testing/tests/ikev2/reauth-mbb-revoked/hosts/carol/etc/strongswan.conf b/testing/tests/ikev2/reauth-mbb-revoked/hosts/carol/etc/strongswan.conf
new file mode 100644
index 000000000..f89437e43
--- /dev/null
+++ b/testing/tests/ikev2/reauth-mbb-revoked/hosts/carol/etc/strongswan.conf
@@ -0,0 +1,7 @@
+# /etc/strongswan.conf - strongSwan configuration file
+
+charon {
+ load = aes des sha1 sha2 md5 pem pkcs1 gmp random nonce x509 curl revocation hmac xcbc stroke kernel-netlink socket-default updown
+
+ make_before_break = yes
+}
diff --git a/testing/tests/ikev2/reauth-mbb-revoked/hosts/moon/etc/ipsec.conf b/testing/tests/ikev2/reauth-mbb-revoked/hosts/moon/etc/ipsec.conf
new file mode 100644
index 000000000..93ae34cf7
--- /dev/null
+++ b/testing/tests/ikev2/reauth-mbb-revoked/hosts/moon/etc/ipsec.conf
@@ -0,0 +1,19 @@
+# /etc/ipsec.conf - strongSwan IPsec configuration file
+
+config setup
+ strictcrlpolicy=yes
+
+conn %default
+ ikelifetime=30m
+ keylife=20m
+ rekeymargin=0s
+ keyingtries=1
+
+conn rw
+ left=PH_IP_MOON
+ leftcert=moonCert.pem
+ leftid=@moon.strongswan.org
+ leftsubnet=10.1.0.0/16
+ right=%any
+ keyexchange=ikev2
+ auto=add
diff --git a/testing/tests/ikev2/reauth-mbb-revoked/hosts/moon/etc/strongswan.conf b/testing/tests/ikev2/reauth-mbb-revoked/hosts/moon/etc/strongswan.conf
new file mode 100644
index 000000000..f585edfca
--- /dev/null
+++ b/testing/tests/ikev2/reauth-mbb-revoked/hosts/moon/etc/strongswan.conf
@@ -0,0 +1,5 @@
+# /etc/strongswan.conf - strongSwan configuration file
+
+charon {
+ load = aes des sha1 sha2 md5 pem pkcs1 gmp random nonce x509 curl revocation hmac xcbc stroke kernel-netlink socket-default updown
+}
diff --git a/testing/tests/ikev2/reauth-mbb-revoked/posttest.dat b/testing/tests/ikev2/reauth-mbb-revoked/posttest.dat
new file mode 100644
index 000000000..d0d591585
--- /dev/null
+++ b/testing/tests/ikev2/reauth-mbb-revoked/posttest.dat
@@ -0,0 +1,3 @@
+winnetou::cp /var/www/strongswan.crl.bak /var/www/strongswan.crl
+moon::ipsec stop
+carol::ipsec stop
diff --git a/testing/tests/ikev2/reauth-mbb-revoked/pretest.dat b/testing/tests/ikev2/reauth-mbb-revoked/pretest.dat
new file mode 100644
index 000000000..3a1982f8a
--- /dev/null
+++ b/testing/tests/ikev2/reauth-mbb-revoked/pretest.dat
@@ -0,0 +1,4 @@
+moon::ipsec start
+carol::ipsec start
+carol::expect-connection home
+carol::ipsec up home
diff --git a/testing/tests/ikev2/reauth-mbb-revoked/test.conf b/testing/tests/ikev2/reauth-mbb-revoked/test.conf
new file mode 100644
index 000000000..4a5fc470f
--- /dev/null
+++ b/testing/tests/ikev2/reauth-mbb-revoked/test.conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This configuration file provides information on the
+# guest instances used for this test
+
+# All guest instances that are required for this test
+#
+VIRTHOSTS="alice moon carol winnetou"
+
+# Corresponding block diagram
+#
+DIAGRAM="a-m-c-w.png"
+
+# Guest instances on which tcpdump is to be started
+#
+TCPDUMPHOSTS="moon"
+
+# Guest instances on which IPsec is started
+# Used for IPsec logging purposes
+#
+IPSECHOSTS="moon carol"