summaryrefslogtreecommitdiff
path: root/src/libcharon/sa
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcharon/sa')
-rw-r--r--src/libcharon/sa/child_sa.c19
-rw-r--r--src/libcharon/sa/ike_sa.c18
-rw-r--r--src/libcharon/sa/ike_sa.h10
-rw-r--r--src/libcharon/sa/ike_sa_manager.c88
-rw-r--r--src/libcharon/sa/ike_sa_manager.h15
-rw-r--r--src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.c4
-rw-r--r--src/libcharon/sa/ikev1/iv_manager.c1
-rw-r--r--src/libcharon/sa/ikev1/tasks/main_mode.c3
-rw-r--r--src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c173
-rw-r--r--src/libcharon/sa/ikev2/keymat_v2.h5
-rw-r--r--src/libcharon/sa/ikev2/task_manager_v2.c22
-rw-r--r--src/libcharon/sa/ikev2/tasks/child_create.c1
-rw-r--r--src/libcharon/sa/ikev2/tasks/child_delete.c2
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_auth.c1
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_init.c15
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_vendor.c2
-rw-r--r--src/libcharon/sa/shunt_manager.c21
17 files changed, 305 insertions, 95 deletions
diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c
index 4133d9182..91da4d3e6 100644
--- a/src/libcharon/sa/child_sa.c
+++ b/src/libcharon/sa/child_sa.c
@@ -254,7 +254,7 @@ struct private_child_sa_t {
};
/**
- * convert an IKEv2 specific protocol identifier to the IP protocol identifier.
+ * Convert an IKEv2 specific protocol identifier to the IP protocol identifier
*/
static inline uint8_t proto_ike2ip(protocol_id_t protocol)
{
@@ -269,6 +269,18 @@ static inline uint8_t proto_ike2ip(protocol_id_t protocol)
}
}
+/**
+ * Returns the mark to use on the inbound SA
+ */
+static inline mark_t mark_in_sa(private_child_sa_t *this)
+{
+ if (this->config->has_option(this->config, OPT_MARK_IN_SA))
+ {
+ return this->mark_in;
+ }
+ return (mark_t){};
+}
+
METHOD(child_sa_t, get_name, char*,
private_child_sa_t *this)
{
@@ -525,6 +537,7 @@ static status_t update_usebytes(private_child_sa_t *this, bool inbound)
.dst = this->my_addr,
.spi = this->my_spi,
.proto = proto_ike2ip(this->protocol),
+ .mark = mark_in_sa(this),
};
kernel_ipsec_query_sa_t query = {};
@@ -857,7 +870,7 @@ static status_t install_internal(private_child_sa_t *this, chunk_t encr,
.dst = dst,
.spi = spi,
.proto = proto_ike2ip(this->protocol),
- .mark = inbound ? (mark_t){} : this->mark_out,
+ .mark = inbound ? mark_in_sa(this) : this->mark_out,
};
sa = (kernel_ipsec_add_sa_t){
.reqid = this->reqid,
@@ -1475,6 +1488,7 @@ METHOD(child_sa_t, update, status_t,
.dst = this->my_addr,
.spi = this->my_spi,
.proto = proto_ike2ip(this->protocol),
+ .mark = mark_in_sa(this),
};
kernel_ipsec_update_sa_t sa = {
.cpi = this->ipcomp != IPCOMP_NONE ? this->my_cpi : 0,
@@ -1660,6 +1674,7 @@ METHOD(child_sa_t, destroy, void,
.dst = this->my_addr,
.spi = this->my_spi,
.proto = proto_ike2ip(this->protocol),
+ .mark = mark_in_sa(this),
};
kernel_ipsec_del_sa_t sa = {
.cpi = this->my_cpi,
diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c
index 045858792..823cf2579 100644
--- a/src/libcharon/sa/ike_sa.c
+++ b/src/libcharon/sa/ike_sa.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006-2016 Tobias Brunner
+ * Copyright (C) 2006-2017 Tobias Brunner
* Copyright (C) 2006 Daniel Roethlisberger
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2005 Jan Hutter
@@ -914,9 +914,15 @@ METHOD(ike_sa_t, set_state, void,
}
METHOD(ike_sa_t, reset, void,
- private_ike_sa_t *this)
+ private_ike_sa_t *this, bool new_spi)
{
- /* the responder ID is reset, as peer may choose another one */
+ /* reset the initiator SPI if requested */
+ if (new_spi)
+ {
+ charon->ike_sa_manager->new_initiator_spi(charon->ike_sa_manager,
+ &this->public);
+ }
+ /* the responder ID is reset, as peer may choose another one */
if (this->ike_sa_id->is_initiator(this->ike_sa_id))
{
this->ike_sa_id->set_responder_spi(this->ike_sa_id, 0);
@@ -1849,7 +1855,7 @@ METHOD(ike_sa_t, reauth, status_t,
{
DBG0(DBG_IKE, "reinitiating IKE_SA %s[%d]",
get_name(this), this->unique_id);
- reset(this);
+ reset(this, TRUE);
return this->task_manager->initiate(this->task_manager);
}
/* we can't reauthenticate as responder when we use EAP or virtual IPs.
@@ -2222,7 +2228,7 @@ static bool redirect_connecting(private_ike_sa_t *this, identification_t *to)
{
return FALSE;
}
- reset(this);
+ reset(this, TRUE);
DESTROY_IF(this->redirected_from);
this->redirected_from = this->other_host->clone(this->other_host);
DESTROY_IF(this->remote_host);
@@ -2351,7 +2357,7 @@ METHOD(ike_sa_t, retransmit, status_t,
{
DBG1(DBG_IKE, "peer not responding, trying again (%d/%d)",
this->keyingtry + 1, tries);
- reset(this);
+ reset(this, TRUE);
resolve_hosts(this);
return this->task_manager->initiate(this->task_manager);
}
diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h
index c8ba2fd2a..fbc367292 100644
--- a/src/libcharon/sa/ike_sa.h
+++ b/src/libcharon/sa/ike_sa.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006-2016 Tobias Brunner
+ * Copyright (C) 2006-2017 Tobias Brunner
* Copyright (C) 2006 Daniel Roethlisberger
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2005 Jan Hutter
@@ -1014,7 +1014,7 @@ struct ike_sa_t {
/**
* Rekey the IKE_SA.
*
- * Sets up a new IKE_SA, moves all CHILDs to it and deletes this IKE_SA.
+ * Sets up a new IKE_SA, moves all CHILD_SAs to it and deletes this IKE_SA.
*
* @return - SUCCESS, if IKE_SA rekeying initiated
*/
@@ -1169,9 +1169,11 @@ struct ike_sa_t {
void (*inherit_post) (ike_sa_t *this, ike_sa_t *other);
/**
- * Reset the IKE_SA, useable when initiating fails
+ * Reset the IKE_SA, useable when initiating fails.
+ *
+ * @param new_spi TRUE to allocate a new initiator SPI
*/
- void (*reset) (ike_sa_t *this);
+ void (*reset) (ike_sa_t *this, bool new_spi);
/**
* Destroys a ike_sa_t object.
diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c
index c0bfebb83..101d98678 100644
--- a/src/libcharon/sa/ike_sa_manager.c
+++ b/src/libcharon/sa/ike_sa_manager.c
@@ -1,9 +1,10 @@
/*
* Copyright (C) 2005-2011 Martin Willi
* Copyright (C) 2011 revosec AG
- * Copyright (C) 2008-2016 Tobias Brunner
+ *
+ * Copyright (C) 2008-2017 Tobias Brunner
* Copyright (C) 2005 Jan Hutter
- * Hochschule fuer Technik Rapperswil
+ * HSR 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
@@ -1572,6 +1573,88 @@ METHOD(ike_sa_manager_t, checkout_by_name, ike_sa_t*,
return ike_sa;
}
+METHOD(ike_sa_manager_t, new_initiator_spi, bool,
+ private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
+{
+ ike_sa_state_t state;
+ ike_sa_id_t *ike_sa_id;
+ entry_t *entry;
+ u_int segment;
+ uint64_t new_spi, spi;
+
+ state = ike_sa->get_state(ike_sa);
+ if (state != IKE_CONNECTING)
+ {
+ DBG1(DBG_MGR, "unable to change initiator SPI for IKE_SA in state "
+ "%N", ike_sa_state_names, state);
+ return FALSE;
+ }
+
+ ike_sa_id = ike_sa->get_id(ike_sa);
+ if (!ike_sa_id->is_initiator(ike_sa_id))
+ {
+ DBG1(DBG_MGR, "unable to change initiator SPI of IKE_SA as responder");
+ return FALSE;
+ }
+
+ if (ike_sa != charon->bus->get_sa(charon->bus))
+ {
+ DBG1(DBG_MGR, "unable to change initiator SPI of IKE_SA not checked "
+ "out by current thread");
+ return FALSE;
+ }
+
+ new_spi = get_spi(this);
+ if (!new_spi)
+ {
+ DBG1(DBG_MGR, "unable to allocate new initiator SPI for IKE_SA");
+ return FALSE;
+ }
+
+ if (get_entry_by_sa(this, ike_sa_id, ike_sa, &entry, &segment) == SUCCESS)
+ {
+ if (entry->driveout_waiting_threads && entry->driveout_new_threads)
+ { /* it looks like flush() has been called and the SA is being deleted
+ * anyway, no need for a new SPI */
+ DBG2(DBG_MGR, "ignored change of initiator SPI during shutdown");
+ unlock_single_segment(this, segment);
+ return FALSE;
+ }
+ /* threads waiting for this entry do so using the (soon) wrong IKE_SA
+ * ID and, therefore, likely on the wrong segment, so drive them out */
+ entry->driveout_waiting_threads = TRUE;
+ entry->driveout_new_threads = TRUE;
+ while (entry->waiting_threads)
+ {
+ entry->condvar->broadcast(entry->condvar);
+ entry->condvar->wait(entry->condvar, this->segments[segment].mutex);
+ }
+ remove_entry(this, entry);
+ unlock_single_segment(this, segment);
+ }
+ else
+ {
+ DBG1(DBG_MGR, "unable to change initiator SPI of IKE_SA, not found");
+ return FALSE;
+ }
+
+ spi = ike_sa_id->get_initiator_spi(ike_sa_id);
+
+ DBG2(DBG_MGR, "change initiator SPI of IKE_SA %s[%u] from %.16"PRIx64" to "
+ "%.16"PRIx64, ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa),
+ be64toh(spi), be64toh(new_spi));
+
+ ike_sa_id->set_initiator_spi(ike_sa_id, new_spi);
+ entry->ike_sa_id->replace_values(entry->ike_sa_id, ike_sa_id);
+
+ entry->driveout_waiting_threads = FALSE;
+ entry->driveout_new_threads = FALSE;
+
+ segment = put_entry(this, entry);
+ unlock_single_segment(this, segment);
+ return TRUE;
+}
+
CALLBACK(enumerator_filter_wait, bool,
private_ike_sa_manager_t *this, enumerator_t *orig, va_list args)
{
@@ -2277,6 +2360,7 @@ ike_sa_manager_t *ike_sa_manager_create()
.checkout_by_config = _checkout_by_config,
.checkout_by_id = _checkout_by_id,
.checkout_by_name = _checkout_by_name,
+ .new_initiator_spi = _new_initiator_spi,
.check_uniqueness = _check_uniqueness,
.has_contact = _has_contact,
.create_enumerator = _create_enumerator,
diff --git a/src/libcharon/sa/ike_sa_manager.h b/src/libcharon/sa/ike_sa_manager.h
index 4298c54e2..efad2e4d6 100644
--- a/src/libcharon/sa/ike_sa_manager.h
+++ b/src/libcharon/sa/ike_sa_manager.h
@@ -1,8 +1,8 @@
/*
- * Copyright (C) 2008-2015 Tobias Brunner
+ * Copyright (C) 2008-2017 Tobias Brunner
* Copyright (C) 2005-2008 Martin Willi
* Copyright (C) 2005 Jan Hutter
- * Hochschule fuer Technik Rapperswil
+ * HSR 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
@@ -109,6 +109,17 @@ struct ike_sa_manager_t {
peer_cfg_t *peer_cfg);
/**
+ * Reset initiator SPI.
+ *
+ * Allocate a new initiator SPI for the given IKE_SA in state IKE_CONNECTING
+ * and update internal data.
+ *
+ * @param ike_sa IKE_SA to update
+ * @return TRUE if SPI successfully changed
+ */
+ bool (*new_initiator_spi)(ike_sa_manager_t* this, ike_sa_t *ike_sa);
+
+ /**
* Check for duplicates of the given IKE_SA.
*
* Measures are taken according to the uniqueness policy of the IKE_SA.
diff --git a/src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.c b/src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.c
index 344c1bf5d..41be15a08 100644
--- a/src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.c
+++ b/src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.c
@@ -110,7 +110,7 @@ METHOD(authenticator_t, build, status_t,
}
free(dh.ptr);
- if (private->sign(private, scheme, hash, &sig))
+ if (private->sign(private, scheme, NULL, hash, &sig))
{
sig_payload = hash_payload_create(PLV1_SIGNATURE);
sig_payload->set_hash(sig_payload, sig);
@@ -176,7 +176,7 @@ METHOD(authenticator_t, process, status_t,
id, auth, TRUE);
while (enumerator->enumerate(enumerator, &public, &current_auth))
{
- if (public->verify(public, scheme, hash, sig))
+ if (public->verify(public, scheme, NULL, hash, sig))
{
DBG1(DBG_IKE, "authentication of '%Y' with %N successful",
id, signature_scheme_names, scheme);
diff --git a/src/libcharon/sa/ikev1/iv_manager.c b/src/libcharon/sa/ikev1/iv_manager.c
index c9f737ccd..2a6e5c04f 100644
--- a/src/libcharon/sa/ikev1/iv_manager.c
+++ b/src/libcharon/sa/ikev1/iv_manager.c
@@ -15,6 +15,7 @@
#include "iv_manager.h"
+#include <library.h>
#include <collections/linked_list.h>
/**
diff --git a/src/libcharon/sa/ikev1/tasks/main_mode.c b/src/libcharon/sa/ikev1/tasks/main_mode.c
index 628ea0de8..4c16adba3 100644
--- a/src/libcharon/sa/ikev1/tasks/main_mode.c
+++ b/src/libcharon/sa/ikev1/tasks/main_mode.c
@@ -221,8 +221,7 @@ static void add_initial_contact(private_main_mode_t *this, message_t *message,
idr = this->ph1->get_id(this->ph1, this->peer_cfg, FALSE);
if (idr && !idr->contains_wildcards(idr))
{
- if (this->peer_cfg->get_unique_policy(this->peer_cfg) != UNIQUE_NO &&
- this->peer_cfg->get_unique_policy(this->peer_cfg) != UNIQUE_NEVER)
+ if (this->peer_cfg->get_unique_policy(this->peer_cfg) != UNIQUE_NEVER)
{
host = this->ike_sa->get_other_host(this->ike_sa);
if (!charon->ike_sa_manager->has_contact(charon->ike_sa_manager,
diff --git a/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c b/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c
index 19ea72d0b..65baf8771 100644
--- a/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c
+++ b/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c
@@ -1,8 +1,8 @@
/*
- * Copyright (C) 2008-2015 Tobias Brunner
+ * Copyright (C) 2008-2017 Tobias Brunner
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2005 Jan Hutter
- * Hochschule fuer Technik Rapperswil
+ * HSR 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
@@ -61,10 +61,9 @@ struct private_pubkey_authenticator_t {
* Parse authentication data used for Signature Authentication as per RFC 7427
*/
static bool parse_signature_auth_data(chunk_t *auth_data, key_type_t *key_type,
- signature_scheme_t *scheme)
+ signature_params_t *params)
{
uint8_t len;
- int oid;
if (!auth_data->len)
{
@@ -72,14 +71,11 @@ static bool parse_signature_auth_data(chunk_t *auth_data, key_type_t *key_type,
}
len = auth_data->ptr[0];
*auth_data = chunk_skip(*auth_data, 1);
- /* we currently don't support schemes that require parameters */
- oid = asn1_parse_algorithmIdentifier(*auth_data, 1, NULL);
- *scheme = signature_scheme_from_oid(oid);
- if (*scheme == SIGN_UNKNOWN)
+ if (!signature_params_parse(*auth_data, 1, params))
{
return FALSE;
}
- *key_type = key_type_from_signature_scheme(*scheme);
+ *key_type = key_type_from_signature_scheme(params->scheme);
*auth_data = chunk_skip(*auth_data, len);
return TRUE;
}
@@ -88,18 +84,16 @@ static bool parse_signature_auth_data(chunk_t *auth_data, key_type_t *key_type,
* Build authentication data used for Signature Authentication as per RFC 7427
*/
static bool build_signature_auth_data(chunk_t *auth_data,
- signature_scheme_t scheme)
+ signature_params_t *params)
{
chunk_t data;
uint8_t len;
- int oid;
- oid = signature_scheme_to_oid(scheme);
- if (oid == OID_UNKNOWN)
+ if (!signature_params_build(params, &data))
{
+ chunk_free(auth_data);
return FALSE;
}
- data = asn1_algorithmIdentifier(oid);
len = data.len;
*auth_data = chunk_cat("cmm", chunk_from_thing(len), data, *auth_data);
return TRUE;
@@ -114,13 +108,13 @@ static array_t *select_signature_schemes(keymat_v2_t *keymat,
{
enumerator_t *enumerator;
signature_scheme_t scheme;
- uintptr_t config;
+ signature_params_t *config;
auth_rule_t rule;
key_type_t key_type;
bool have_config = FALSE;
array_t *selected;
- selected = array_create(sizeof(signature_scheme_t), 0);
+ selected = array_create(0, 0);
key_type = private->get_type(private);
enumerator = auth->create_enumerator(auth);
while (enumerator->enumerate(enumerator, &rule, &config))
@@ -130,12 +124,12 @@ static array_t *select_signature_schemes(keymat_v2_t *keymat,
continue;
}
have_config = TRUE;
- if (key_type == key_type_from_signature_scheme(config) &&
+ if (key_type == key_type_from_signature_scheme(config->scheme) &&
keymat->hash_algorithm_supported(keymat,
- hasher_from_signature_scheme(config)))
+ hasher_from_signature_scheme(config->scheme,
+ config->params)))
{
- scheme = config;
- array_insert(selected, ARRAY_TAIL, &scheme);
+ array_insert(selected, ARRAY_TAIL, signature_params_clone(config));
}
}
enumerator->destroy(enumerator);
@@ -146,24 +140,30 @@ static array_t *select_signature_schemes(keymat_v2_t *keymat,
* and supported by the other peer */
enumerator = signature_schemes_for_key(key_type,
private->get_keysize(private));
- while (enumerator->enumerate(enumerator, &scheme))
+ while (enumerator->enumerate(enumerator, &config))
{
+ if (config->scheme == SIGN_RSA_EMSA_PSS &&
+ !lib->settings->get_bool(lib->settings, "%s.rsa_pss", FALSE,
+ lib->ns))
+ {
+ continue;
+ }
if (keymat->hash_algorithm_supported(keymat,
- hasher_from_signature_scheme(scheme)))
+ hasher_from_signature_scheme(config->scheme,
+ config->params)))
{
- array_insert(selected, ARRAY_TAIL, &scheme);
+ array_insert(selected, ARRAY_TAIL,
+ signature_params_clone(config));
}
}
enumerator->destroy(enumerator);
- /* for RSA we tried at least SHA-512, also try other schemes down to
- * what we'd use with classic authentication */
+ /* for RSA we tried at least SHA-512, also try other schemes */
if (key_type == KEY_RSA)
{
signature_scheme_t schemes[] = {
SIGN_RSA_EMSA_PKCS1_SHA2_384,
SIGN_RSA_EMSA_PKCS1_SHA2_256,
- SIGN_RSA_EMSA_PKCS1_SHA1,
}, contained;
bool found;
int i, j;
@@ -182,9 +182,13 @@ static array_t *select_signature_schemes(keymat_v2_t *keymat,
}
}
if (!found && keymat->hash_algorithm_supported(keymat,
- hasher_from_signature_scheme(scheme)))
+ hasher_from_signature_scheme(scheme,
+ NULL)))
{
- array_insert(selected, ARRAY_TAIL, &scheme);
+ INIT(config,
+ .scheme = scheme,
+ )
+ array_insert(selected, ARRAY_TAIL, config);
}
}
}
@@ -192,6 +196,12 @@ static array_t *select_signature_schemes(keymat_v2_t *keymat,
return selected;
}
+CALLBACK(destroy_scheme, void,
+ signature_params_t *params, int idx, void *user)
+{
+ signature_params_destroy(params);
+}
+
/**
* Create a signature using RFC 7427 signature authentication
*/
@@ -201,7 +211,7 @@ static status_t sign_signature_auth(private_pubkey_authenticator_t *this,
{
enumerator_t *enumerator;
keymat_v2_t *keymat;
- signature_scheme_t scheme = SIGN_UNKNOWN, *schemep;
+ signature_params_t *params = NULL;
array_t *schemes;
chunk_t octets = chunk_empty;
status_t status = FAILED;
@@ -221,11 +231,11 @@ static status_t sign_signature_auth(private_pubkey_authenticator_t *this,
schemes))
{
enumerator = array_create_enumerator(schemes);
- while (enumerator->enumerate(enumerator, &schemep))
+ while (enumerator->enumerate(enumerator, &params))
{
- scheme = *schemep;
- if (private->sign(private, scheme, octets, auth_data) &&
- build_signature_auth_data(auth_data, scheme))
+ if (private->sign(private, params->scheme, params->params, octets,
+ auth_data) &&
+ build_signature_auth_data(auth_data, params))
{
status = SUCCESS;
break;
@@ -233,16 +243,34 @@ static status_t sign_signature_auth(private_pubkey_authenticator_t *this,
else
{
DBG2(DBG_IKE, "unable to create %N signature for %N key",
- signature_scheme_names, scheme, key_type_names,
+ signature_scheme_names, params->scheme, key_type_names,
private->get_type(private));
}
}
enumerator->destroy(enumerator);
}
- DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N %s", id,
- signature_scheme_names, scheme,
- status == SUCCESS ? "successful" : "failed");
- array_destroy(schemes);
+ if (params)
+ {
+ if (params->scheme == SIGN_RSA_EMSA_PSS)
+ {
+ rsa_pss_params_t *pss = params->params;
+ DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N_%N %s", id,
+ signature_scheme_names, params->scheme,
+ hash_algorithm_short_names_upper, pss->hash,
+ status == SUCCESS ? "successful" : "failed");
+ }
+ else
+ {
+ DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N %s", id,
+ signature_scheme_names, params->scheme,
+ status == SUCCESS ? "successful" : "failed");
+ }
+ }
+ else
+ {
+ DBG1(DBG_IKE, "authentication of '%Y' (myself) failed", id);
+ }
+ array_destroy_function(schemes, destroy_scheme, NULL);
chunk_free(&octets);
return status;
}
@@ -253,23 +281,27 @@ static status_t sign_signature_auth(private_pubkey_authenticator_t *this,
*/
static bool get_auth_octets_scheme(private_pubkey_authenticator_t *this,
bool verify, identification_t *id,
- chunk_t *octets, signature_scheme_t *scheme)
+ chunk_t *octets, signature_params_t **scheme)
{
keymat_v2_t *keymat;
array_t *schemes;
bool success = FALSE;
- schemes = array_create(sizeof(signature_scheme_t), 0);
- array_insert(schemes, ARRAY_TAIL, scheme);
+ schemes = array_create(0, 0);
+ array_insert(schemes, ARRAY_TAIL, *scheme);
keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa);
if (keymat->get_auth_octets(keymat, verify, this->ike_sa_init, this->nonce,
id, this->reserved, octets, schemes) &&
- array_get(schemes, 0, &scheme))
+ array_remove(schemes, 0, scheme))
{
success = TRUE;
}
- array_destroy(schemes);
+ else
+ {
+ *scheme = NULL;
+ }
+ array_destroy_function(schemes, destroy_scheme, NULL);
return success;
}
@@ -282,6 +314,7 @@ static status_t sign_classic(private_pubkey_authenticator_t *this,
chunk_t *auth_data)
{
signature_scheme_t scheme;
+ signature_params_t *params;
chunk_t octets = chunk_empty;
status_t status = FAILED;
@@ -319,11 +352,18 @@ static status_t sign_classic(private_pubkey_authenticator_t *this,
return FAILED;
}
- if (get_auth_octets_scheme(this, FALSE, id, &octets, &scheme) &&
- private->sign(private, scheme, octets, auth_data))
+ INIT(params,
+ .scheme = scheme,
+ );
+ if (get_auth_octets_scheme(this, FALSE, id, &octets, &params) &&
+ private->sign(private, params->scheme, NULL, octets, auth_data))
{
status = SUCCESS;
}
+ if (params)
+ {
+ signature_params_destroy(params);
+ }
DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N %s", id,
auth_method_names, *auth_method,
status == SUCCESS ? "successful" : "failed");
@@ -385,7 +425,7 @@ METHOD(authenticator_t, process, status_t,
auth_cfg_t *auth, *current_auth;
enumerator_t *enumerator;
key_type_t key_type = KEY_ECDSA;
- signature_scheme_t scheme;
+ signature_params_t *params;
status_t status = NOT_FOUND;
const char *reason = "unsupported";
bool online;
@@ -395,25 +435,26 @@ METHOD(authenticator_t, process, status_t,
{
return FAILED;
}
+ INIT(params);
auth_method = auth_payload->get_auth_method(auth_payload);
auth_data = auth_payload->get_data(auth_payload);
switch (auth_method)
{
case AUTH_RSA:
key_type = KEY_RSA;
- scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
+ params->scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
break;
case AUTH_ECDSA_256:
- scheme = SIGN_ECDSA_256;
+ params->scheme = SIGN_ECDSA_256;
break;
case AUTH_ECDSA_384:
- scheme = SIGN_ECDSA_384;
+ params->scheme = SIGN_ECDSA_384;
break;
case AUTH_ECDSA_521:
- scheme = SIGN_ECDSA_521;
+ params->scheme = SIGN_ECDSA_521;
break;
case AUTH_DS:
- if (parse_signature_auth_data(&auth_data, &key_type, &scheme))
+ if (parse_signature_auth_data(&auth_data, &key_type, params))
{
break;
}
@@ -422,10 +463,11 @@ METHOD(authenticator_t, process, status_t,
default:
DBG1(DBG_IKE, "%N authentication %s", auth_method_names,
auth_method, reason);
+ signature_params_destroy(params);
return INVALID_ARG;
}
id = this->ike_sa->get_other_id(this->ike_sa);
- if (!get_auth_octets_scheme(this, TRUE, id, &octets, &scheme))
+ if (!get_auth_octets_scheme(this, TRUE, id, &octets, &params))
{
return FAILED;
}
@@ -436,15 +478,31 @@ METHOD(authenticator_t, process, status_t,
key_type, id, auth, online);
while (enumerator->enumerate(enumerator, &public, &current_auth))
{
- if (public->verify(public, scheme, octets, auth_data))
+ if (public->verify(public, params->scheme, params->params, octets,
+ auth_data))
{
- DBG1(DBG_IKE, "authentication of '%Y' with %N successful", id,
- auth_method == AUTH_DS ? signature_scheme_names : auth_method_names,
- auth_method == AUTH_DS ? scheme : auth_method);
+ if (auth_method != AUTH_DS)
+ {
+ DBG1(DBG_IKE, "authentication of '%Y' with %N successful", id,
+ auth_method_names, auth_method);
+ }
+ else if (params->scheme == SIGN_RSA_EMSA_PSS)
+ {
+ rsa_pss_params_t *pss = params->params;
+ DBG1(DBG_IKE, "authentication of '%Y' with %N_%N successful",
+ id, signature_scheme_names, params->scheme,
+ hash_algorithm_short_names_upper, pss->hash);
+ }
+ else
+ {
+ DBG1(DBG_IKE, "authentication of '%Y' with %N successful", id,
+ signature_scheme_names, params->scheme);
+ }
status = SUCCESS;
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);
+ auth->add(auth, AUTH_RULE_IKE_SIGNATURE_SCHEME,
+ signature_params_clone(params));
if (!online)
{
auth->add(auth, AUTH_RULE_CERT_VALIDATION_SUSPENDED, TRUE);
@@ -459,6 +517,7 @@ METHOD(authenticator_t, process, status_t,
}
enumerator->destroy(enumerator);
chunk_free(&octets);
+ signature_params_destroy(params);
if (status == NOT_FOUND)
{
DBG1(DBG_IKE, "no trusted %N public key found for '%Y'",
diff --git a/src/libcharon/sa/ikev2/keymat_v2.h b/src/libcharon/sa/ikev2/keymat_v2.h
index 36bf149fe..084ed40f0 100644
--- a/src/libcharon/sa/ikev2/keymat_v2.h
+++ b/src/libcharon/sa/ikev2/keymat_v2.h
@@ -101,8 +101,9 @@ struct keymat_v2_t {
* @param id identity
* @param reserved reserved bytes of id_payload
* @param octests chunk receiving allocated auth octets
- * @param schemes array containing signature schemes in case they
- * need to be modified by the keymat implementation
+ * @param schemes array containing signature schemes
+ * (signature_params_t*) in case they need to be
+ * modified by the keymat implementation
* @return TRUE if octets created successfully
*/
bool (*get_auth_octets)(keymat_v2_t *this, bool verify, chunk_t ike_sa_init,
diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c
index c2ddbc588..361eb0fe1 100644
--- a/src/libcharon/sa/ikev2/task_manager_v2.c
+++ b/src/libcharon/sa/ikev2/task_manager_v2.c
@@ -131,7 +131,7 @@ struct private_task_manager_t {
array_t *queued_tasks;
/**
- * Array of active tasks, initiated by ourselve
+ * Array of active tasks, initiated by ourselves
*/
array_t *active_tasks;
@@ -1780,9 +1780,11 @@ static void trigger_mbb_reauth(private_task_manager_t *this)
enumerator_t *enumerator;
child_sa_t *child_sa;
child_cfg_t *cfg;
+ peer_cfg_t *peer;
ike_sa_t *new;
host_t *host;
queued_task_t *queued;
+ bool children = FALSE;
new = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager,
this->ike_sa->get_version(this->ike_sa), TRUE);
@@ -1791,7 +1793,8 @@ static void trigger_mbb_reauth(private_task_manager_t *this)
return;
}
- new->set_peer_cfg(new, this->ike_sa->get_peer_cfg(this->ike_sa));
+ peer = this->ike_sa->get_peer_cfg(this->ike_sa);
+ new->set_peer_cfg(new, peer);
host = this->ike_sa->get_other_host(this->ike_sa);
new->set_other_host(new, host->clone(host));
host = this->ike_sa->get_my_host(this->ike_sa);
@@ -1809,6 +1812,7 @@ static void trigger_mbb_reauth(private_task_manager_t *this)
cfg = child_sa->get_config(child_sa);
new->queue_task(new, &child_create_create(new, cfg->get_ref(cfg),
FALSE, NULL, NULL)->task);
+ children = TRUE;
}
enumerator->destroy(enumerator);
@@ -1821,10 +1825,24 @@ static void trigger_mbb_reauth(private_task_manager_t *this)
new->queue_task(new, queued->task);
array_remove_at(this->queued_tasks, enumerator);
free(queued);
+ children = TRUE;
}
}
enumerator->destroy(enumerator);
+ if (!children
+#ifdef ME
+ /* allow reauth of mediation connections without CHILD_SAs */
+ && !peer->is_mediation(peer)
+#endif /* ME */
+ )
+ {
+ charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, new);
+ DBG1(DBG_IKE, "unable to reauthenticate IKE_SA, no CHILD_SA "
+ "to recreate");
+ return;
+ }
+
/* suspend online revocation checking until the SA is established */
new->set_condition(new, COND_ONLINE_VALIDATION_SUSPENDED, TRUE);
diff --git a/src/libcharon/sa/ikev2/tasks/child_create.c b/src/libcharon/sa/ikev2/tasks/child_create.c
index cac3bc0a2..4d4d72e0b 100644
--- a/src/libcharon/sa/ikev2/tasks/child_create.c
+++ b/src/libcharon/sa/ikev2/tasks/child_create.c
@@ -1377,7 +1377,6 @@ METHOD(task_t, build_r, status_t,
uint16_t group = htons(this->dh_group);
message->add_notify(message, FALSE, INVALID_KE_PAYLOAD,
chunk_from_thing(group));
- handle_child_sa_failure(this, message);
return SUCCESS;
}
case FAILED:
diff --git a/src/libcharon/sa/ikev2/tasks/child_delete.c b/src/libcharon/sa/ikev2/tasks/child_delete.c
index 2217295b6..164f8fc03 100644
--- a/src/libcharon/sa/ikev2/tasks/child_delete.c
+++ b/src/libcharon/sa/ikev2/tasks/child_delete.c
@@ -349,7 +349,7 @@ static status_t destroy_and_reestablish(private_child_delete_t *this)
child_sa->get_unique_id(child_sa)), delay);
continue;
}
- else if (expire)
+ else if (now < expire)
{ /* let it expire naturally */
continue;
}
diff --git a/src/libcharon/sa/ikev2/tasks/ike_auth.c b/src/libcharon/sa/ikev2/tasks/ike_auth.c
index 53daaf2ad..aeaa701c9 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_auth.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_auth.c
@@ -471,7 +471,6 @@ METHOD(task_t, build_i, status_t,
if (idr && !idr->contains_wildcards(idr) &&
message->get_message_id(message) == 1 &&
- this->peer_cfg->get_unique_policy(this->peer_cfg) != UNIQUE_NO &&
this->peer_cfg->get_unique_policy(this->peer_cfg) != UNIQUE_NEVER)
{
host_t *host;
diff --git a/src/libcharon/sa/ikev2/tasks/ike_init.c b/src/libcharon/sa/ikev2/tasks/ike_init.c
index 58b710616..d75d21715 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_init.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_init.c
@@ -158,7 +158,7 @@ static void send_supported_hash_algorithms(private_ike_init_t *this,
peer_cfg_t *peer;
auth_cfg_t *auth;
auth_rule_t rule;
- uintptr_t config;
+ signature_params_t *config;
int written;
size_t len = BUF_LEN;
char buf[len];
@@ -177,7 +177,8 @@ static void send_supported_hash_algorithms(private_ike_init_t *this,
{
if (rule == AUTH_RULE_IKE_SIGNATURE_SCHEME)
{
- hash = hasher_from_signature_scheme(config);
+ hash = hasher_from_signature_scheme(config->scheme,
+ config->params);
if (hasher_algorithm_for_ikev2(hash))
{
algos->add(algos, hash);
@@ -502,7 +503,11 @@ static void process_payloads(private_ike_init_t *this, message_t *message)
this->dh = this->keymat->keymat.create_dh(
&this->keymat->keymat, this->dh_group);
}
- if (this->dh)
+ else if (this->dh)
+ {
+ this->dh_failed = this->dh->get_dh_group(this->dh) != this->dh_group;
+ }
+ if (this->dh && !this->dh_failed)
{
this->dh_failed = !this->dh->set_other_public_value(this->dh,
ke_payload->get_key_exchange_data(ke_payload));
@@ -811,7 +816,7 @@ METHOD(task_t, process_i, status_t,
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, FALSE);
}
enumerator->destroy(enumerator);
@@ -829,7 +834,7 @@ METHOD(task_t, process_i, status_t,
{
chunk_free(&this->cookie);
this->cookie = chunk_clone(notify->get_notification_data(notify));
- this->ike_sa->reset(this->ike_sa);
+ this->ike_sa->reset(this->ike_sa, FALSE);
enumerator->destroy(enumerator);
DBG2(DBG_IKE, "received %N notify", notify_type_names, type);
this->retry++;
diff --git a/src/libcharon/sa/ikev2/tasks/ike_vendor.c b/src/libcharon/sa/ikev2/tasks/ike_vendor.c
index e85b276e8..f72fbc437 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_vendor.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_vendor.c
@@ -97,6 +97,8 @@ static vid_data_t vids[] = {
"\x88\x2f\xe5\x6d\x6f\xd2\x0d\xbc\x22\x51\x61\x3b\x2e\xbe\x5b\xeb"},
{ "Cisco Delete Reason", 0, NULL, 0,
"CISCO-DELETE-REASON" },
+ { "Cisco FlexVPN Supported", 0, NULL, 0,
+ "FLEXVPN-SUPPORTED" },
{ "Cisco Copyright (c) 2009", 0, NULL, 0,
"CISCO(COPYRIGHT)&Copyright (c) 2009 Cisco Systems, Inc." },
{ "FRAGMENTATION", 0, NULL, 16,
diff --git a/src/libcharon/sa/shunt_manager.c b/src/libcharon/sa/shunt_manager.c
index ad12f0579..3a254cea5 100644
--- a/src/libcharon/sa/shunt_manager.c
+++ b/src/libcharon/sa/shunt_manager.c
@@ -96,6 +96,7 @@ static bool install_shunt_policy(child_cfg_t *child)
status_t status = SUCCESS;
uint32_t manual_prio;
char *interface;
+ bool fwd_out;
ipsec_sa_cfg_t sa = { .mode = MODE_TRANSPORT };
switch (child->get_mode(child))
@@ -122,6 +123,7 @@ static bool install_shunt_policy(child_cfg_t *child)
manual_prio = child->get_manual_prio(child);
interface = child->get_interface(child);
+ fwd_out = child->has_option(child, OPT_FWD_OUT_POLICIES);
/* enumerate pairs of traffic selectors */
e_my_ts = my_ts_list->create_enumerator(my_ts_list);
@@ -157,9 +159,11 @@ static bool install_shunt_policy(child_cfg_t *child)
.sa = &sa,
};
status |= charon->kernel->add_policy(charon->kernel, &id, &policy);
- /* install "outbound" forward policy */
- id.dir = POLICY_FWD;
- status |= charon->kernel->add_policy(charon->kernel, &id, &policy);
+ if (fwd_out)
+ { /* install "outbound" forward policy */
+ id.dir = POLICY_FWD;
+ status |= charon->kernel->add_policy(charon->kernel, &id, &policy);
+ }
/* install in policy */
id = (kernel_ipsec_policy_id_t){
.dir = POLICY_IN,
@@ -255,6 +259,7 @@ static void uninstall_shunt_policy(child_cfg_t *child)
status_t status = SUCCESS;
uint32_t manual_prio;
char *interface;
+ bool fwd_out;
ipsec_sa_cfg_t sa = { .mode = MODE_TRANSPORT };
switch (child->get_mode(child))
@@ -281,6 +286,7 @@ static void uninstall_shunt_policy(child_cfg_t *child)
manual_prio = child->get_manual_prio(child);
interface = child->get_interface(child);
+ fwd_out = child->has_option(child, OPT_FWD_OUT_POLICIES);
/* enumerate pairs of traffic selectors */
e_my_ts = my_ts_list->create_enumerator(my_ts_list);
@@ -316,9 +322,12 @@ static void uninstall_shunt_policy(child_cfg_t *child)
.sa = &sa,
};
status |= charon->kernel->del_policy(charon->kernel, &id, &policy);
- /* uninstall "outbound" forward policy */
- id.dir = POLICY_FWD;
- status |= charon->kernel->del_policy(charon->kernel, &id, &policy);
+ if (fwd_out)
+ {
+ /* uninstall "outbound" forward policy */
+ id.dir = POLICY_FWD;
+ status |= charon->kernel->del_policy(charon->kernel, &id, &policy);
+ }
/* uninstall in policy */
id = (kernel_ipsec_policy_id_t){
.dir = POLICY_IN,