summaryrefslogtreecommitdiff
path: root/src/libcharon/sa
diff options
context:
space:
mode:
authorYves-Alexis Perez <corsac@debian.org>2018-09-24 15:11:14 +0200
committerYves-Alexis Perez <corsac@debian.org>2018-09-24 15:11:14 +0200
commite0e280b7669435b991b7e457abd8aa450930b3e8 (patch)
tree3e6084f13b14ad2df104e2ce6e589eb96c5f7ac9 /src/libcharon/sa
parent51a71ee15c1bcf0e82f363a16898f571e211f9c3 (diff)
downloadvyos-strongswan-e0e280b7669435b991b7e457abd8aa450930b3e8.tar.gz
vyos-strongswan-e0e280b7669435b991b7e457abd8aa450930b3e8.zip
New upstream version 5.7.0
Diffstat (limited to 'src/libcharon/sa')
-rw-r--r--src/libcharon/sa/authenticator.h13
-rw-r--r--src/libcharon/sa/child_sa.c11
-rw-r--r--src/libcharon/sa/ike_sa.c1
-rw-r--r--src/libcharon/sa/ike_sa.h10
-rw-r--r--src/libcharon/sa/ike_sa_manager.c32
-rw-r--r--src/libcharon/sa/ikev1/keymat_v1.c1
-rw-r--r--src/libcharon/sa/ikev1/phase1.c2
-rw-r--r--src/libcharon/sa/ikev1/task_manager_v1.c8
-rw-r--r--src/libcharon/sa/ikev1/tasks/aggressive_mode.c22
-rw-r--r--src/libcharon/sa/ikev1/tasks/isakmp_vendor.c2
-rw-r--r--src/libcharon/sa/ikev1/tasks/main_mode.c21
-rw-r--r--src/libcharon/sa/ikev1/tasks/mode_config.c1
-rw-r--r--src/libcharon/sa/ikev1/tasks/quick_mode.c2
-rw-r--r--src/libcharon/sa/ikev1/tasks/xauth.c2
-rw-r--r--src/libcharon/sa/ikev2/authenticators/eap_authenticator.c56
-rw-r--r--src/libcharon/sa/ikev2/authenticators/psk_authenticator.c60
-rw-r--r--src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c171
-rw-r--r--src/libcharon/sa/ikev2/keymat_v2.c136
-rw-r--r--src/libcharon/sa/ikev2/keymat_v2.h20
-rw-r--r--src/libcharon/sa/ikev2/task_manager_v2.c5
-rw-r--r--src/libcharon/sa/ikev2/tasks/child_create.c20
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_auth.c352
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_auth_lifetime.h2
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_init.c159
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_mobike.c4
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_mobike.h2
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_rekey.c2
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_vendor.c2
-rw-r--r--src/libcharon/sa/shunt_manager.c12
-rw-r--r--src/libcharon/sa/task.h6
-rw-r--r--src/libcharon/sa/trap_manager.c6
31 files changed, 939 insertions, 204 deletions
diff --git a/src/libcharon/sa/authenticator.h b/src/libcharon/sa/authenticator.h
index 42d9ce32e..58a8ca04f 100644
--- a/src/libcharon/sa/authenticator.h
+++ b/src/libcharon/sa/authenticator.h
@@ -1,6 +1,6 @@
/*
+ * Copyright (C) 2008-2018 Tobias Brunner
* Copyright (C) 2005-2009 Martin Willi
- * Copyright (C) 2008 Tobias Brunner
* Copyright (C) 2005 Jan Hutter
* HSR Hochschule fuer Technik Rapperswil
*
@@ -157,6 +157,17 @@ struct authenticator_t {
status_t (*build)(authenticator_t *this, message_t *message);
/**
+ * Optional method to set a Postquantum Preshared Key (PPK) to be used
+ * during authentication.
+ *
+ * Has to be called before the final call to process()/build().
+ *
+ * @param ppk PPK to use
+ * @param no_ppk_auth whether to add a NO_PPK_AUTH notify in build()
+ */
+ void (*use_ppk)(authenticator_t *this, chunk_t ppk, bool no_ppk_auth);
+
+ /**
* Check if the authenticator is capable of mutual authentication.
*
* Some authenticator authenticate both peers, e.g. EAP. To support
diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c
index 7eeb578f3..c33398bee 100644
--- a/src/libcharon/sa/child_sa.c
+++ b/src/libcharon/sa/child_sa.c
@@ -890,12 +890,21 @@ static status_t install_internal(private_child_sa_t *this, chunk_t encr,
.cpi = cpi,
.encap = this->encap,
.hw_offload = this->config->get_hw_offload(this->config),
+ .mark = this->config->get_set_mark(this->config, inbound),
.esn = esn,
+ .copy_df = !this->config->has_option(this->config, OPT_NO_COPY_DF),
+ .copy_ecn = !this->config->has_option(this->config, OPT_NO_COPY_ECN),
+ .copy_dscp = this->config->get_copy_dscp(this->config),
.initiator = initiator,
.inbound = inbound,
.update = update,
};
+ if (sa.mark.value == MARK_SAME)
+ {
+ sa.mark.value = inbound ? this->mark_in.value : this->mark_out.value;
+ }
+
status = charon->kernel->add_sa(charon->kernel, &id, &sa);
my_ts->destroy(my_ts);
@@ -1723,7 +1732,7 @@ static host_t* get_proxy_addr(child_cfg_t *config, host_t *ike, bool local)
traffic_selector_t *ts;
list = linked_list_create_with_items(ike, NULL);
- ts_list = config->get_traffic_selectors(config, local, NULL, list);
+ ts_list = config->get_traffic_selectors(config, local, NULL, list, FALSE);
list->destroy(list);
enumerator = ts_list->create_enumerator(ts_list);
diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c
index f39fed6f0..a4ad866d3 100644
--- a/src/libcharon/sa/ike_sa.c
+++ b/src/libcharon/sa/ike_sa.c
@@ -674,6 +674,7 @@ METHOD(ike_sa_t, get_ike_cfg, ike_cfg_t*,
METHOD(ike_sa_t, set_ike_cfg, void,
private_ike_sa_t *this, ike_cfg_t *ike_cfg)
{
+ DESTROY_IF(this->ike_cfg);
ike_cfg->get_ref(ike_cfg);
this->ike_cfg = ike_cfg;
}
diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h
index 316b713ee..c1d3e1d7a 100644
--- a/src/libcharon/sa/ike_sa.h
+++ b/src/libcharon/sa/ike_sa.h
@@ -156,6 +156,11 @@ enum ike_extension_t {
* IKEv2 Message ID sync, RFC 6311
*/
EXT_IKE_MESSAGE_ID_SYNC = (1<<14),
+
+ /**
+ * Postquantum Preshared Keys, draft-ietf-ipsecme-qr-ikev2
+ */
+ EXT_PPK = (1<<15),
};
/**
@@ -227,6 +232,11 @@ enum ike_condition_t {
* Online certificate revocation checking is suspended for this IKE_SA
*/
COND_ONLINE_VALIDATION_SUSPENDED = (1<<12),
+
+ /**
+ * A Postquantum Preshared Key was used when this IKE_SA was created
+ */
+ COND_PPK = (1<<13),
};
/**
diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c
index 2a499db40..c50c70860 100644
--- a/src/libcharon/sa/ike_sa_manager.c
+++ b/src/libcharon/sa/ike_sa_manager.c
@@ -2,7 +2,7 @@
* Copyright (C) 2005-2011 Martin Willi
* Copyright (C) 2011 revosec AG
*
- * Copyright (C) 2008-2017 Tobias Brunner
+ * Copyright (C) 2008-2018 Tobias Brunner
* Copyright (C) 2005 Jan Hutter
* HSR Hochschule fuer Technik Rapperswil
*
@@ -1620,17 +1620,6 @@ METHOD(ike_sa_manager_t, new_initiator_spi, bool,
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
{
@@ -1638,7 +1627,19 @@ METHOD(ike_sa_manager_t, new_initiator_spi, bool,
return FALSE;
}
+ /* the hashtable row and segment are determined by the local SPI as
+ * initiator, so if we change it the row and segment derived from it might
+ * change as well. This could be a problem for threads waiting for the
+ * entry (in particular those enumerating entries to check them out by
+ * unique ID or name). In order to avoid having to drive them out and thus
+ * preventing them from checking out the entry (even though the ID or name
+ * will not change and enumerating it is also fine), we mask the new SPI and
+ * merge it with the old SPI so the entry ends up in the same row/segment.
+ * Since SPIs are 64-bit and the number of rows/segments is usually
+ * relatively low this should not be a problem. */
spi = ike_sa_id->get_initiator_spi(ike_sa_id);
+ new_spi = (spi & (uint64_t)this->table_mask) |
+ (new_spi & ~(uint64_t)this->table_mask);
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),
@@ -1647,10 +1648,7 @@ METHOD(ike_sa_manager_t, new_initiator_spi, bool,
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);
+ entry->condvar->signal(entry->condvar);
unlock_single_segment(this, segment);
return TRUE;
}
@@ -2017,6 +2015,8 @@ static status_t enforce_replace(private_ike_sa_manager_t *this,
* CHILD_SAs to keep connectivity up. */
lib->scheduler->schedule_job(lib->scheduler, (job_t*)
delete_ike_sa_job_create(duplicate->get_id(duplicate), TRUE), 10);
+ DBG1(DBG_IKE, "schedule delete of duplicate IKE_SA for peer '%Y' due "
+ "to uniqueness policy and suspected reauthentication", other);
return SUCCESS;
}
DBG1(DBG_IKE, "deleting duplicate IKE_SA for peer '%Y' due to "
diff --git a/src/libcharon/sa/ikev1/keymat_v1.c b/src/libcharon/sa/ikev1/keymat_v1.c
index 1de05b4ec..bcea1f388 100644
--- a/src/libcharon/sa/ikev1/keymat_v1.c
+++ b/src/libcharon/sa/ikev1/keymat_v1.c
@@ -219,7 +219,6 @@ static aead_t *create_aead(proposal_t *proposal, prf_t *prf, chunk_t skeyid_e,
encryption_algorithm_names, alg, key_size);
return NULL;
}
- key_size = crypter->get_key_size(crypter);
if (!expand_skeyid_e(skeyid_e, crypter->get_key_size(crypter), prf, ka))
{
return NULL;
diff --git a/src/libcharon/sa/ikev1/phase1.c b/src/libcharon/sa/ikev1/phase1.c
index 5856f829e..b99d75142 100644
--- a/src/libcharon/sa/ikev1/phase1.c
+++ b/src/libcharon/sa/ikev1/phase1.c
@@ -311,7 +311,7 @@ static void save_auth_cfg(private_phase1_t *this,
return;
}
auth = auth_cfg_create();
- /* for local config, we _copy_ entires from the config, as it contains
+ /* for local config, we _copy_ entries from the config, as it contains
* certificates we must send later. */
auth->merge(auth, this->ike_sa->get_auth_cfg(this->ike_sa, local), local);
this->ike_sa->add_auth_cfg(this->ike_sa, local, auth);
diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c
index 3472d2c35..5f6c3bbe8 100644
--- a/src/libcharon/sa/ikev1/task_manager_v1.c
+++ b/src/libcharon/sa/ikev1/task_manager_v1.c
@@ -721,6 +721,7 @@ METHOD(task_manager_t, initiate, status_t,
{
case IKE_CONNECTING:
/* close after sending an INFORMATIONAL when unestablished */
+ charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
return FAILED;
case IKE_DELETING:
/* close after sending a DELETE */
@@ -920,15 +921,16 @@ static bool process_dpd(private_task_manager_t *this, message_t *message)
}
else /* DPD_R_U_THERE_ACK */
{
- if (seq == this->dpd_send - 1)
+ if (seq == this->dpd_send)
{
+ this->dpd_send++;
this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND,
time_monotonic(NULL));
}
else
{
DBG1(DBG_IKE, "received invalid DPD sequence number %u "
- "(expected %u), ignored", seq, this->dpd_send - 1);
+ "(expected %u), ignored", seq, this->dpd_send);
}
}
return TRUE;
@@ -1843,7 +1845,7 @@ METHOD(task_manager_t, queue_dpd, void,
uint32_t t, retransmit;
queue_task(this, (task_t*)isakmp_dpd_create(this->ike_sa, DPD_R_U_THERE,
- this->dpd_send++));
+ this->dpd_send));
peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
/* compute timeout in milliseconds */
diff --git a/src/libcharon/sa/ikev1/tasks/aggressive_mode.c b/src/libcharon/sa/ikev1/tasks/aggressive_mode.c
index 82d647a6c..023119dd4 100644
--- a/src/libcharon/sa/ikev1/tasks/aggressive_mode.c
+++ b/src/libcharon/sa/ikev1/tasks/aggressive_mode.c
@@ -270,11 +270,6 @@ METHOD(task_t, build_i, status_t,
return FAILED;
}
id = this->ph1->get_id(this->ph1, this->peer_cfg, TRUE);
- if (!id)
- {
- DBG1(DBG_CFG, "own identity not known");
- return FAILED;
- }
this->ike_sa->set_my_id(this->ike_sa, id->clone(id));
id_payload = id_payload_create_from_identification(PLV1_ID, id);
this->id_data = id_payload->get_encoded(id_payload);
@@ -302,6 +297,7 @@ METHOD(task_t, build_i, status_t,
this->id_data))
{
this->id_data = chunk_empty;
+ charon->bus->alert(charon->bus, ALERT_LOCAL_AUTH_FAILED);
return send_notify(this, AUTHENTICATION_FAILED);
}
this->id_data = chunk_empty;
@@ -330,6 +326,7 @@ METHOD(task_t, build_i, status_t,
}
if (!establish(this))
{
+ charon->bus->alert(charon->bus, ALERT_PEER_AUTH_FAILED);
return send_notify(this, AUTHENTICATION_FAILED);
}
break;
@@ -428,6 +425,7 @@ METHOD(task_t, process_r, status_t,
{
DBG1(DBG_IKE, "Aggressive Mode PSK disabled for "
"security reasons");
+ charon->bus->alert(charon->bus, ALERT_PEER_AUTH_FAILED);
return send_notify(this, AUTHENTICATION_FAILED);
}
break;
@@ -455,6 +453,7 @@ METHOD(task_t, process_r, status_t,
if (!id_payload)
{
DBG1(DBG_IKE, "IDii payload missing");
+ charon->bus->alert(charon->bus, ALERT_PEER_AUTH_FAILED);
return send_notify(this, INVALID_PAYLOAD_TYPE);
}
@@ -465,6 +464,7 @@ METHOD(task_t, process_r, status_t,
this->method, TRUE, id);
if (!this->peer_cfg)
{
+ charon->bus->alert(charon->bus, ALERT_PEER_AUTH_FAILED);
return send_notify(this, AUTHENTICATION_FAILED);
}
this->ike_sa->set_peer_cfg(this->ike_sa, this->peer_cfg);
@@ -493,6 +493,7 @@ METHOD(task_t, process_r, status_t,
this->method, TRUE, NULL);
if (!this->peer_cfg)
{
+ charon->bus->alert(charon->bus, ALERT_PEER_AUTH_FAILED);
return send_delete(this);
}
this->ike_sa->set_peer_cfg(this->ike_sa, this->peer_cfg);
@@ -502,6 +503,7 @@ METHOD(task_t, process_r, status_t,
{
DBG1(DBG_IKE, "Aggressive Mode authorization hook forbids "
"IKE_SA, cancelling");
+ charon->bus->alert(charon->bus, ALERT_PEER_AUTH_FAILED);
return send_delete(this);
}
@@ -528,6 +530,7 @@ METHOD(task_t, process_r, status_t,
}
if (!establish(this))
{
+ charon->bus->alert(charon->bus, ALERT_PEER_AUTH_FAILED);
return send_delete(this);
}
job = adopt_children_job_create(
@@ -602,11 +605,6 @@ METHOD(task_t, build_r, status_t,
}
id = this->ph1->get_id(this->ph1, this->peer_cfg, TRUE);
- if (!id)
- {
- DBG1(DBG_CFG, "own identity not known");
- return send_notify(this, INVALID_ID_INFORMATION);
- }
this->ike_sa->set_my_id(this->ike_sa, id->clone(id));
id_payload = id_payload_create_from_identification(PLV1_ID, id);
@@ -615,6 +613,7 @@ METHOD(task_t, build_r, status_t,
if (!this->ph1->build_auth(this->ph1, this->method, message,
id_payload->get_encoded(id_payload)))
{
+ charon->bus->alert(charon->bus, ALERT_LOCAL_AUTH_FAILED);
return send_notify(this, AUTHENTICATION_FAILED);
}
return NEED_MORE;
@@ -679,6 +678,7 @@ METHOD(task_t, process_i, status_t,
if (!id_payload)
{
DBG1(DBG_IKE, "IDir payload missing");
+ charon->bus->alert(charon->bus, ALERT_PEER_AUTH_FAILED);
return send_delete(this);
}
id = id_payload->get_identification(id_payload);
@@ -687,6 +687,7 @@ METHOD(task_t, process_i, status_t,
{
DBG1(DBG_IKE, "IDir '%Y' does not match to '%Y'", id, cid);
id->destroy(id);
+ charon->bus->alert(charon->bus, ALERT_PEER_AUTH_FAILED);
return send_notify(this, INVALID_ID_INFORMATION);
}
this->ike_sa->set_other_id(this->ike_sa, id);
@@ -698,6 +699,7 @@ METHOD(task_t, process_i, status_t,
if (!this->ph1->verify_auth(this->ph1, this->method, message,
id_payload->get_encoded(id_payload)))
{
+ charon->bus->alert(charon->bus, ALERT_PEER_AUTH_FAILED);
return send_notify(this, AUTHENTICATION_FAILED);
}
if (!charon->bus->authorize(charon->bus, FALSE))
diff --git a/src/libcharon/sa/ikev1/tasks/isakmp_vendor.c b/src/libcharon/sa/ikev1/tasks/isakmp_vendor.c
index 6a296f221..b26a11bb4 100644
--- a/src/libcharon/sa/ikev1/tasks/isakmp_vendor.c
+++ b/src/libcharon/sa/ikev1/tasks/isakmp_vendor.c
@@ -59,7 +59,7 @@ struct private_isakmp_vendor_t {
ike_sa_t *ike_sa;
/**
- * Are we the inititator of this task
+ * Are we the initiator of this task
*/
bool initiator;
diff --git a/src/libcharon/sa/ikev1/tasks/main_mode.c b/src/libcharon/sa/ikev1/tasks/main_mode.c
index 1f764e547..b60c84992 100644
--- a/src/libcharon/sa/ikev1/tasks/main_mode.c
+++ b/src/libcharon/sa/ikev1/tasks/main_mode.c
@@ -332,11 +332,6 @@ METHOD(task_t, build_i, status_t,
identification_t *id;
id = this->ph1->get_id(this->ph1, this->peer_cfg, TRUE);
- if (!id)
- {
- DBG1(DBG_CFG, "own identity not known");
- return send_notify(this, INVALID_ID_INFORMATION);
- }
this->ike_sa->set_my_id(this->ike_sa, id->clone(id));
id_payload = id_payload_create_from_identification(PLV1_ID, id);
message->add_payload(message, &id_payload->payload_interface);
@@ -344,6 +339,7 @@ METHOD(task_t, build_i, status_t,
if (!this->ph1->build_auth(this->ph1, this->method, message,
id_payload->get_encoded(id_payload)))
{
+ charon->bus->alert(charon->bus, ALERT_LOCAL_AUTH_FAILED);
return send_notify(this, AUTHENTICATION_FAILED);
}
@@ -445,6 +441,7 @@ METHOD(task_t, process_r, status_t,
if (!id_payload)
{
DBG1(DBG_IKE, "IDii payload missing");
+ charon->bus->alert(charon->bus, ALERT_PEER_AUTH_FAILED);
return send_notify(this, INVALID_PAYLOAD_TYPE);
}
id = id_payload->get_identification(id_payload);
@@ -457,6 +454,7 @@ METHOD(task_t, process_r, status_t,
this->method, FALSE, id);
if (!this->peer_cfg)
{
+ charon->bus->alert(charon->bus, ALERT_PEER_AUTH_FAILED);
return send_notify(this, AUTHENTICATION_FAILED);
}
this->ike_sa->set_peer_cfg(this->ike_sa, this->peer_cfg);
@@ -472,6 +470,7 @@ METHOD(task_t, process_r, status_t,
{
DBG1(DBG_IKE, "Main Mode authorization hook forbids IKE_SA, "
"cancelling");
+ charon->bus->alert(charon->bus, ALERT_PEER_AUTH_FAILED);
return send_notify(this, AUTHENTICATION_FAILED);
}
@@ -523,11 +522,6 @@ METHOD(task_t, build_r, status_t,
xauth_t *xauth = NULL;
id = this->ph1->get_id(this->ph1, this->peer_cfg, TRUE);
- if (!id)
- {
- DBG1(DBG_CFG, "own identity not known");
- return send_notify(this, INVALID_ID_INFORMATION);
- }
this->ike_sa->set_my_id(this->ike_sa, id->clone(id));
id_payload = id_payload_create_from_identification(PLV1_ID, id);
@@ -536,6 +530,7 @@ METHOD(task_t, build_r, status_t,
if (!this->ph1->build_auth(this->ph1, this->method, message,
id_payload->get_encoded(id_payload)))
{
+ charon->bus->alert(charon->bus, ALERT_LOCAL_AUTH_FAILED);
return send_notify(this, AUTHENTICATION_FAILED);
}
@@ -562,6 +557,7 @@ METHOD(task_t, build_r, status_t,
}
if (!establish(this))
{
+ charon->bus->alert(charon->bus, ALERT_PEER_AUTH_FAILED);
return send_notify(this, AUTHENTICATION_FAILED);
}
job = adopt_children_job_create(
@@ -688,6 +684,7 @@ METHOD(task_t, process_i, status_t,
if (!id_payload)
{
DBG1(DBG_IKE, "IDir payload missing");
+ charon->bus->alert(charon->bus, ALERT_PEER_AUTH_FAILED);
return send_delete(this);
}
id = id_payload->get_identification(id_payload);
@@ -696,6 +693,7 @@ METHOD(task_t, process_i, status_t,
{
DBG1(DBG_IKE, "IDir '%Y' does not match to '%Y'", id, cid);
id->destroy(id);
+ charon->bus->alert(charon->bus, ALERT_PEER_AUTH_FAILED);
return send_delete(this);
}
this->ike_sa->set_other_id(this->ike_sa, id);
@@ -703,12 +701,14 @@ METHOD(task_t, process_i, status_t,
if (!this->ph1->verify_auth(this->ph1, this->method, message,
id_payload->get_encoded(id_payload)))
{
+ charon->bus->alert(charon->bus, ALERT_PEER_AUTH_FAILED);
return send_delete(this);
}
if (!charon->bus->authorize(charon->bus, FALSE))
{
DBG1(DBG_IKE, "Main Mode authorization hook forbids IKE_SA, "
"cancelling");
+ charon->bus->alert(charon->bus, ALERT_PEER_AUTH_FAILED);
return send_delete(this);
}
@@ -736,6 +736,7 @@ METHOD(task_t, process_i, status_t,
}
if (!establish(this))
{
+ charon->bus->alert(charon->bus, ALERT_PEER_AUTH_FAILED);
return send_delete(this);
}
break;
diff --git a/src/libcharon/sa/ikev1/tasks/mode_config.c b/src/libcharon/sa/ikev1/tasks/mode_config.c
index 43897c304..9b692588d 100644
--- a/src/libcharon/sa/ikev1/tasks/mode_config.c
+++ b/src/libcharon/sa/ikev1/tasks/mode_config.c
@@ -583,7 +583,6 @@ static status_t build_ack(private_mode_config_t *this, message_t *message)
enumerator = this->vips->create_enumerator(this->vips);
while (enumerator->enumerate(enumerator, &host))
{
- type = INTERNAL_IP6_ADDRESS;
if (host->get_family(host) == AF_INET6)
{
type = INTERNAL_IP6_ADDRESS;
diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c
index 5e5b61e7f..007e94d96 100644
--- a/src/libcharon/sa/ikev1/tasks/quick_mode.c
+++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c
@@ -544,7 +544,7 @@ static traffic_selector_t* select_ts(private_quick_mode_t *this, bool local,
hosts = get_dynamic_hosts(this->ike_sa, local);
list = this->config->get_traffic_selectors(this->config,
- local, supplied, hosts);
+ local, supplied, hosts, TRUE);
hosts->destroy(hosts);
if (list->get_first(list, (void**)&ts) == SUCCESS)
{
diff --git a/src/libcharon/sa/ikev1/tasks/xauth.c b/src/libcharon/sa/ikev1/tasks/xauth.c
index 968b4386c..bec2cfe7d 100644
--- a/src/libcharon/sa/ikev1/tasks/xauth.c
+++ b/src/libcharon/sa/ikev1/tasks/xauth.c
@@ -226,7 +226,7 @@ static bool select_compliant_config(private_xauth_t *this)
{ /* current config is fine */
return TRUE;
}
- DBG1(DBG_CFG, "selected peer config '%s' inacceptable",
+ DBG1(DBG_CFG, "selected peer config '%s' unacceptable",
old->get_name(old));
aggressive = old->use_aggressive(old);
diff --git a/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c b/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c
index bcf262725..e1e6cd7ee 100644
--- a/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c
+++ b/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Tobias Brunner
+ * Copyright (C) 2012-2018 Tobias Brunner
* Copyright (C) 2006-2009 Martin Willi
* HSR Hochschule fuer Technik Rapperswil
*
@@ -65,6 +65,16 @@ struct private_eap_authenticator_t {
char reserved[3];
/**
+ * PPK to use
+ */
+ chunk_t ppk;
+
+ /**
+ * Add a NO_PPK_AUTH notify
+ */
+ bool no_ppk_auth;
+
+ /**
* Current EAP method processing
*/
eap_method_t *method;
@@ -444,6 +454,7 @@ static bool verify_auth(private_eap_authenticator_t *this, message_t *message,
chunk_t nonce, chunk_t init)
{
auth_payload_t *auth_payload;
+ notify_payload_t *notify;
chunk_t auth_data, recv_auth_data;
identification_t *other_id;
auth_cfg_t *auth;
@@ -458,14 +469,26 @@ static bool verify_auth(private_eap_authenticator_t *this, message_t *message,
DBG1(DBG_IKE, "AUTH payload missing");
return FALSE;
}
+ recv_auth_data = auth_payload->get_data(auth_payload);
+
+ if (this->ike_sa->supports_extension(this->ike_sa, EXT_PPK) &&
+ !this->ppk.ptr)
+ { /* look for a NO_PPK_AUTH notify if we have no PPK */
+ notify = message->get_notify(message, NO_PPK_AUTH);
+ if (notify)
+ {
+ DBG1(DBG_IKE, "no PPK available, using NO_PPK_AUTH notify");
+ recv_auth_data = notify->get_notification_data(notify);
+ }
+ }
+
other_id = this->ike_sa->get_other_id(this->ike_sa);
keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa);
- if (!keymat->get_psk_sig(keymat, TRUE, init, nonce,
- this->msk, other_id, this->reserved, &auth_data))
+ if (!keymat->get_psk_sig(keymat, TRUE, init, nonce, this->msk, this->ppk,
+ other_id, this->reserved, &auth_data))
{
return FALSE;
}
- recv_auth_data = auth_payload->get_data(auth_payload);
if (!auth_data.len || !chunk_equals_const(auth_data, recv_auth_data))
{
DBG1(DBG_IKE, "verification of AUTH payload with%s EAP MSK failed",
@@ -507,8 +530,8 @@ static bool build_auth(private_eap_authenticator_t *this, message_t *message,
DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N",
my_id, auth_class_names, AUTH_CLASS_EAP);
- if (!keymat->get_psk_sig(keymat, FALSE, init, nonce,
- this->msk, my_id, this->reserved, &auth_data))
+ if (!keymat->get_psk_sig(keymat, FALSE, init, nonce, this->msk, this->ppk,
+ my_id, this->reserved, &auth_data))
{
return FALSE;
}
@@ -517,6 +540,18 @@ static bool build_auth(private_eap_authenticator_t *this, message_t *message,
auth_payload->set_data(auth_payload, auth_data);
message->add_payload(message, (payload_t*)auth_payload);
chunk_free(&auth_data);
+
+ if (this->no_ppk_auth)
+ {
+ if (!keymat->get_psk_sig(keymat, FALSE, init, nonce, this->msk,
+ chunk_empty, my_id, this->reserved, &auth_data))
+ {
+ DBG1(DBG_IKE, "failed adding NO_PPK_AUTH notify");
+ return FALSE;
+ }
+ message->add_notify(message, FALSE, NO_PPK_AUTH, auth_data);
+ chunk_free(&auth_data);
+ }
return TRUE;
}
@@ -698,6 +733,13 @@ METHOD(authenticator_t, is_mutual, bool,
return TRUE;
}
+METHOD(authenticator_t, use_ppk, void,
+ private_eap_authenticator_t *this, chunk_t ppk, bool no_ppk_auth)
+{
+ this->ppk = ppk;
+ this->no_ppk_auth = no_ppk_auth;
+}
+
METHOD(authenticator_t, destroy, void,
private_eap_authenticator_t *this)
{
@@ -723,6 +765,7 @@ eap_authenticator_t *eap_authenticator_create_builder(ike_sa_t *ike_sa,
.authenticator = {
.build = _build_client,
.process = _process_client,
+ .use_ppk = _use_ppk,
.is_mutual = _is_mutual,
.destroy = _destroy,
},
@@ -753,6 +796,7 @@ eap_authenticator_t *eap_authenticator_create_verifier(ike_sa_t *ike_sa,
.authenticator = {
.build = _build_server,
.process = _process_server,
+ .use_ppk = _use_ppk,
.is_mutual = _is_mutual,
.destroy = _destroy,
},
diff --git a/src/libcharon/sa/ikev2/authenticators/psk_authenticator.c b/src/libcharon/sa/ikev2/authenticators/psk_authenticator.c
index c1decb130..76571e702 100644
--- a/src/libcharon/sa/ikev2/authenticators/psk_authenticator.c
+++ b/src/libcharon/sa/ikev2/authenticators/psk_authenticator.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2018 Tobias Brunner
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2005 Jan Hutter
* HSR Hochschule fuer Technik Rapperswil
@@ -51,6 +52,16 @@ struct private_psk_authenticator_t {
* Reserved bytes of ID payload
*/
char reserved[3];
+
+ /**
+ * PPK to use
+ */
+ chunk_t ppk;
+
+ /**
+ * Add a NO_PPK_AUTH notify
+ */
+ bool no_ppk_auth;
};
METHOD(authenticator_t, build, status_t,
@@ -68,18 +79,19 @@ METHOD(authenticator_t, build, status_t,
DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N",
my_id, auth_method_names, AUTH_PSK);
key = lib->credmgr->get_shared(lib->credmgr, SHARED_IKE, my_id, other_id);
- if (key == NULL)
+ if (!key)
{
DBG1(DBG_IKE, "no shared key found for '%Y' - '%Y'", my_id, other_id);
return NOT_FOUND;
}
if (!keymat->get_psk_sig(keymat, FALSE, this->ike_sa_init, this->nonce,
- key->get_key(key), my_id, this->reserved, &auth_data))
+ key->get_key(key), this->ppk, my_id,
+ this->reserved, &auth_data))
{
key->destroy(key);
return FAILED;
}
- key->destroy(key);
+
DBG2(DBG_IKE, "successfully created shared key MAC");
auth_payload = auth_payload_create();
auth_payload->set_auth_method(auth_payload, AUTH_PSK);
@@ -87,6 +99,21 @@ METHOD(authenticator_t, build, status_t,
chunk_free(&auth_data);
message->add_payload(message, (payload_t*)auth_payload);
+ if (this->no_ppk_auth)
+ {
+ if (!keymat->get_psk_sig(keymat, FALSE, this->ike_sa_init, this->nonce,
+ key->get_key(key), chunk_empty, my_id,
+ this->reserved, &auth_data))
+ {
+ DBG1(DBG_IKE, "failed adding NO_PPK_AUTH notify");
+ key->destroy(key);
+ return SUCCESS;
+ }
+ DBG2(DBG_IKE, "successfully created shared key MAC without PPK");
+ message->add_notify(message, FALSE, NO_PPK_AUTH, auth_data);
+ chunk_free(&auth_data);
+ }
+ key->destroy(key);
return SUCCESS;
}
@@ -96,6 +123,7 @@ METHOD(authenticator_t, process, status_t,
chunk_t auth_data, recv_auth_data;
identification_t *my_id, *other_id;
auth_payload_t *auth_payload;
+ notify_payload_t *notify;
auth_cfg_t *auth;
shared_key_t *key;
enumerator_t *enumerator;
@@ -108,8 +136,20 @@ METHOD(authenticator_t, process, status_t,
{
return FAILED;
}
- keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa);
recv_auth_data = auth_payload->get_data(auth_payload);
+
+ if (this->ike_sa->supports_extension(this->ike_sa, EXT_PPK) &&
+ !this->ppk.ptr)
+ { /* look for a NO_PPK_AUTH notify if we have no PPK */
+ notify = message->get_notify(message, NO_PPK_AUTH);
+ if (notify)
+ {
+ DBG1(DBG_IKE, "no PPK available, using NO_PPK_AUTH notify");
+ recv_auth_data = notify->get_notification_data(notify);
+ }
+ }
+
+ keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa);
my_id = this->ike_sa->get_my_id(this->ike_sa);
other_id = this->ike_sa->get_other_id(this->ike_sa);
enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr,
@@ -119,7 +159,8 @@ METHOD(authenticator_t, process, status_t,
keys_found++;
if (!keymat->get_psk_sig(keymat, TRUE, this->ike_sa_init, this->nonce,
- key->get_key(key), other_id, this->reserved, &auth_data))
+ key->get_key(key), this->ppk, other_id,
+ this->reserved, &auth_data))
{
continue;
}
@@ -150,6 +191,13 @@ METHOD(authenticator_t, process, status_t,
return SUCCESS;
}
+METHOD(authenticator_t, use_ppk, void,
+ private_psk_authenticator_t *this, chunk_t ppk, bool no_ppk_auth)
+{
+ this->ppk = ppk;
+ this->no_ppk_auth = no_ppk_auth;
+}
+
METHOD(authenticator_t, destroy, void,
private_psk_authenticator_t *this)
{
@@ -170,6 +218,7 @@ psk_authenticator_t *psk_authenticator_create_builder(ike_sa_t *ike_sa,
.authenticator = {
.build = _build,
.process = (void*)return_failed,
+ .use_ppk = _use_ppk,
.is_mutual = (void*)return_false,
.destroy = _destroy,
},
@@ -197,6 +246,7 @@ psk_authenticator_t *psk_authenticator_create_verifier(ike_sa_t *ike_sa,
.authenticator = {
.build = (void*)return_failed,
.process = _process,
+ .use_ppk = _use_ppk,
.is_mutual = (void*)return_false,
.destroy = _destroy,
},
diff --git a/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c b/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c
index 652b837fe..1fcef03cc 100644
--- a/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c
+++ b/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c
@@ -56,6 +56,16 @@ struct private_pubkey_authenticator_t {
* Reserved bytes of ID payload
*/
char reserved[3];
+
+ /**
+ * PPK to use
+ */
+ chunk_t ppk;
+
+ /**
+ * Add a NO_PPK_AUTH notify
+ */
+ bool no_ppk_auth;
};
/**
@@ -204,17 +214,42 @@ CALLBACK(destroy_scheme, void,
}
/**
+ * Adds the given auth data to the message, either in an AUTH payload or
+ * a NO_PPK_AUTH notify.
+ *
+ * The data is freed.
+ */
+static void add_auth_to_message(message_t *message, auth_method_t method,
+ chunk_t data, bool notify)
+{
+ auth_payload_t *auth_payload;
+
+ if (notify)
+ {
+ message->add_notify(message, FALSE, NO_PPK_AUTH, data);
+ }
+ else
+ {
+ auth_payload = auth_payload_create();
+ auth_payload->set_auth_method(auth_payload, method);
+ auth_payload->set_data(auth_payload, data);
+ message->add_payload(message, (payload_t*)auth_payload);
+ }
+ chunk_free(&data);
+}
+
+/**
* Create a signature using RFC 7427 signature authentication
*/
static status_t sign_signature_auth(private_pubkey_authenticator_t *this,
- auth_cfg_t *auth, private_key_t *private,
- identification_t *id, chunk_t *auth_data)
+ auth_cfg_t *auth, private_key_t *private,
+ identification_t *id, message_t *message)
{
enumerator_t *enumerator;
keymat_v2_t *keymat;
signature_params_t *params = NULL;
array_t *schemes;
- chunk_t octets = chunk_empty;
+ chunk_t octets = chunk_empty, auth_data;
status_t status = FAILED;
keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa);
@@ -227,26 +262,46 @@ static status_t sign_signature_auth(private_pubkey_authenticator_t *this,
return FAILED;
}
- if (keymat->get_auth_octets(keymat, FALSE, this->ike_sa_init,
- this->nonce, id, this->reserved, &octets,
- schemes))
+ if (keymat->get_auth_octets(keymat, FALSE, this->ike_sa_init, this->nonce,
+ this->ppk, id, this->reserved, &octets, schemes))
{
enumerator = array_create_enumerator(schemes);
while (enumerator->enumerate(enumerator, &params))
{
- if (private->sign(private, params->scheme, params->params, octets,
- auth_data) &&
- build_signature_auth_data(auth_data, params))
- {
- status = SUCCESS;
- break;
- }
- else
+ if (!private->sign(private, params->scheme, params->params, octets,
+ &auth_data) ||
+ !build_signature_auth_data(&auth_data, params))
{
DBG2(DBG_IKE, "unable to create %N signature for %N key",
signature_scheme_names, params->scheme, key_type_names,
private->get_type(private));
+ continue;
}
+ add_auth_to_message(message, AUTH_DS, auth_data, FALSE);
+ status = SUCCESS;
+
+ if (this->no_ppk_auth)
+ {
+ chunk_free(&octets);
+
+ if (keymat->get_auth_octets(keymat, FALSE, this->ike_sa_init,
+ this->nonce, chunk_empty, id,
+ this->reserved, &octets, schemes) &&
+ private->sign(private, params->scheme, params->params,
+ octets, &auth_data) &&
+ build_signature_auth_data(&auth_data, params))
+ {
+ add_auth_to_message(message, AUTH_DS, auth_data, TRUE);
+ }
+ else
+ {
+ DBG2(DBG_IKE, "unable to create %N signature for %N key "
+ "without PPK", signature_scheme_names, params->scheme,
+ key_type_names, private->get_type(private));
+ status = FAILED;
+ }
+ }
+ break;
}
enumerator->destroy(enumerator);
}
@@ -281,8 +336,8 @@ static status_t sign_signature_auth(private_pubkey_authenticator_t *this,
* keymat).
*/
static bool get_auth_octets_scheme(private_pubkey_authenticator_t *this,
- bool verify, identification_t *id,
- chunk_t *octets, signature_params_t **scheme)
+ bool verify, identification_t *id, chunk_t ppk,
+ chunk_t *octets, signature_params_t **scheme)
{
keymat_v2_t *keymat;
array_t *schemes;
@@ -293,7 +348,8 @@ static bool get_auth_octets_scheme(private_pubkey_authenticator_t *this,
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) &&
+ ppk, id, this->reserved, octets,
+ schemes) &&
array_remove(schemes, 0, scheme))
{
success = TRUE;
@@ -311,19 +367,19 @@ static bool get_auth_octets_scheme(private_pubkey_authenticator_t *this,
*/
static status_t sign_classic(private_pubkey_authenticator_t *this,
auth_cfg_t *auth, private_key_t *private,
- identification_t *id, auth_method_t *auth_method,
- chunk_t *auth_data)
+ identification_t *id, message_t *message)
{
signature_scheme_t scheme;
signature_params_t *params;
- chunk_t octets = chunk_empty;
+ auth_method_t auth_method = AUTH_NONE;
+ chunk_t octets = chunk_empty, auth_data;
status_t status = FAILED;
switch (private->get_type(private))
{
case KEY_RSA:
scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
- *auth_method = AUTH_RSA;
+ auth_method = AUTH_RSA;
break;
case KEY_ECDSA:
/* deduct the signature scheme from the keysize */
@@ -331,15 +387,15 @@ static status_t sign_classic(private_pubkey_authenticator_t *this,
{
case 256:
scheme = SIGN_ECDSA_256;
- *auth_method = AUTH_ECDSA_256;
+ auth_method = AUTH_ECDSA_256;
break;
case 384:
scheme = SIGN_ECDSA_384;
- *auth_method = AUTH_ECDSA_384;
+ auth_method = AUTH_ECDSA_384;
break;
case 521:
scheme = SIGN_ECDSA_521;
- *auth_method = AUTH_ECDSA_521;
+ auth_method = AUTH_ECDSA_521;
break;
default:
DBG1(DBG_IKE, "%d bit ECDSA private key size not supported",
@@ -356,17 +412,34 @@ static status_t sign_classic(private_pubkey_authenticator_t *this,
INIT(params,
.scheme = scheme,
);
- if (get_auth_octets_scheme(this, FALSE, id, &octets, &params) &&
- private->sign(private, params->scheme, NULL, octets, auth_data))
+ if (get_auth_octets_scheme(this, FALSE, id, this->ppk, &octets, &params) &&
+ private->sign(private, params->scheme, NULL, octets, &auth_data))
{
+ add_auth_to_message(message, auth_method, auth_data, FALSE);
status = SUCCESS;
+
+ if (this->no_ppk_auth)
+ {
+ chunk_free(&octets);
+ if (get_auth_octets_scheme(this, FALSE, id, chunk_empty, &octets,
+ &params) &&
+ private->sign(private, params->scheme, NULL, octets,
+ &auth_data))
+ {
+ add_auth_to_message(message, auth_method, auth_data, TRUE);
+ }
+ else
+ {
+ status = FAILED;
+ }
+ }
}
if (params)
{
signature_params_destroy(params);
}
DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N %s", id,
- auth_method_names, *auth_method,
+ auth_method_names, auth_method,
status == SUCCESS ? "successful" : "failed");
chunk_free(&octets);
return status;
@@ -378,10 +451,7 @@ METHOD(authenticator_t, build, status_t,
private_key_t *private;
identification_t *id;
auth_cfg_t *auth;
- chunk_t auth_data;
status_t status;
- auth_payload_t *auth_payload;
- auth_method_t auth_method = AUTH_NONE;
id = this->ike_sa->get_my_id(this->ike_sa);
auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
@@ -394,24 +464,13 @@ METHOD(authenticator_t, build, status_t,
if (this->ike_sa->supports_extension(this->ike_sa, EXT_SIGNATURE_AUTH))
{
- auth_method = AUTH_DS;
- status = sign_signature_auth(this, auth, private, id, &auth_data);
+ status = sign_signature_auth(this, auth, private, id, message);
}
else
{
- status = sign_classic(this, auth, private, id, &auth_method,
- &auth_data);
+ status = sign_classic(this, auth, private, id, message);
}
private->destroy(private);
-
- if (status == SUCCESS)
- {
- auth_payload = auth_payload_create();
- auth_payload->set_auth_method(auth_payload, auth_method);
- auth_payload->set_data(auth_payload, auth_data);
- chunk_free(&auth_data);
- message->add_payload(message, (payload_t*)auth_payload);
- }
return status;
}
@@ -444,6 +503,7 @@ METHOD(authenticator_t, process, status_t,
public_key_t *public;
auth_method_t auth_method;
auth_payload_t *auth_payload;
+ notify_payload_t *notify;
chunk_t auth_data, octets;
identification_t *id;
auth_cfg_t *auth, *current_auth;
@@ -459,9 +519,21 @@ 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);
+
+ if (this->ike_sa->supports_extension(this->ike_sa, EXT_PPK) &&
+ !this->ppk.ptr)
+ { /* look for a NO_PPK_AUTH notify if we have no PPK */
+ notify = message->get_notify(message, NO_PPK_AUTH);
+ if (notify)
+ {
+ DBG1(DBG_IKE, "no PPK available, using NO_PPK_AUTH notify");
+ auth_data = notify->get_notification_data(notify);
+ }
+ }
+
+ INIT(params);
switch (auth_method)
{
case AUTH_RSA:
@@ -491,7 +563,7 @@ METHOD(authenticator_t, process, status_t,
return INVALID_ARG;
}
id = this->ike_sa->get_other_id(this->ike_sa);
- if (!get_auth_octets_scheme(this, TRUE, id, &octets, &params))
+ if (!get_auth_octets_scheme(this, TRUE, id, this->ppk, &octets, &params))
{
return FAILED;
}
@@ -551,6 +623,13 @@ METHOD(authenticator_t, process, status_t,
return status;
}
+METHOD(authenticator_t, use_ppk, void,
+ private_pubkey_authenticator_t *this, chunk_t ppk, bool no_ppk_auth)
+{
+ this->ppk = ppk;
+ this->no_ppk_auth = no_ppk_auth;
+}
+
METHOD(authenticator_t, destroy, void,
private_pubkey_authenticator_t *this)
{
@@ -571,6 +650,7 @@ pubkey_authenticator_t *pubkey_authenticator_create_builder(ike_sa_t *ike_sa,
.authenticator = {
.build = _build,
.process = (void*)return_failed,
+ .use_ppk = _use_ppk,
.is_mutual = (void*)return_false,
.destroy = _destroy,
},
@@ -598,6 +678,7 @@ pubkey_authenticator_t *pubkey_authenticator_create_verifier(ike_sa_t *ike_sa,
.authenticator = {
.build = (void*)return_failed,
.process = _process,
+ .use_ppk = _use_ppk,
.is_mutual = (void*)return_false,
.destroy = _destroy,
},
diff --git a/src/libcharon/sa/ikev2/keymat_v2.c b/src/libcharon/sa/ikev2/keymat_v2.c
index f8b23b66e..db46b816b 100644
--- a/src/libcharon/sa/ikev2/keymat_v2.c
+++ b/src/libcharon/sa/ikev2/keymat_v2.c
@@ -491,6 +491,93 @@ failure:
return this->skp_build.len && this->skp_verify.len;
}
+/**
+ * Derives a key from the given key and a PRF that was initialized with a PPK
+ */
+static bool derive_ppk_key(prf_t *prf, char *name, chunk_t key,
+ chunk_t *new_key)
+{
+ prf_plus_t *prf_plus;
+
+ prf_plus = prf_plus_create(prf, TRUE, key);
+ if (!prf_plus ||
+ !prf_plus->allocate_bytes(prf_plus, key.len, new_key))
+ {
+ DBG1(DBG_IKE, "unable to derive %s with PPK", name);
+ DESTROY_IF(prf_plus);
+ return FALSE;
+ }
+ prf_plus->destroy(prf_plus);
+ return TRUE;
+}
+
+/**
+ * Use the given PPK to derive a new SK_pi/r
+ */
+static bool derive_skp_ppk(private_keymat_v2_t *this, chunk_t ppk, chunk_t skp,
+ chunk_t *new_skp)
+{
+ if (!this->prf->set_key(this->prf, ppk))
+ {
+ DBG1(DBG_IKE, "unable to set PPK in PRF");
+ return FALSE;
+ }
+ return derive_ppk_key(this->prf, "SK_p", skp, new_skp);
+}
+
+METHOD(keymat_v2_t, derive_ike_keys_ppk, bool,
+ private_keymat_v2_t *this, chunk_t ppk)
+{
+ chunk_t skd = chunk_empty, new_skpi = chunk_empty, new_skpr = chunk_empty;
+ chunk_t *skpi, *skpr;
+
+ if (!this->skd.ptr)
+ {
+ return FALSE;
+ }
+
+ if (this->initiator)
+ {
+ skpi = &this->skp_build;
+ skpr = &this->skp_verify;
+ }
+ else
+ {
+ skpi = &this->skp_verify;
+ skpr = &this->skp_build;
+ }
+
+ DBG4(DBG_IKE, "derive keys using PPK %B", &ppk);
+
+ if (!this->prf->set_key(this->prf, ppk))
+ {
+ DBG1(DBG_IKE, "unable to set PPK in PRF");
+ return FALSE;
+ }
+ if (!derive_ppk_key(this->prf, "Sk_d", this->skd, &skd) ||
+ !derive_ppk_key(this->prf, "Sk_pi", *skpi, &new_skpi) ||
+ !derive_ppk_key(this->prf, "Sk_pr", *skpr, &new_skpr))
+ {
+ chunk_clear(&skd);
+ chunk_clear(&new_skpi);
+ chunk_clear(&new_skpr);
+ return FALSE;
+ }
+
+ DBG4(DBG_IKE, "Sk_d secret %B", &skd);
+ chunk_clear(&this->skd);
+ this->skd = skd;
+
+ DBG4(DBG_IKE, "Sk_pi secret %B", &new_skpi);
+ chunk_clear(skpi);
+ *skpi = new_skpi;
+
+ DBG4(DBG_IKE, "Sk_pr secret %B", &new_skpr);
+ chunk_clear(skpr);
+ *skpr = new_skpr;
+ return TRUE;
+}
+
METHOD(keymat_v2_t, derive_child_keys, bool,
private_keymat_v2_t *this, proposal_t *proposal, diffie_hellman_t *dh,
chunk_t nonce_i, chunk_t nonce_r, chunk_t *encr_i, chunk_t *integ_i,
@@ -632,13 +719,23 @@ METHOD(keymat_t, get_aead, aead_t*,
METHOD(keymat_v2_t, get_auth_octets, bool,
private_keymat_v2_t *this, bool verify, chunk_t ike_sa_init,
- chunk_t nonce, identification_t *id, char reserved[3], chunk_t *octets,
- array_t *schemes)
+ chunk_t nonce, chunk_t ppk, identification_t *id, char reserved[3],
+ chunk_t *octets, array_t *schemes)
{
chunk_t chunk, idx;
+ chunk_t skp_ppk = chunk_empty;
chunk_t skp;
skp = verify ? this->skp_verify : this->skp_build;
+ if (ppk.ptr)
+ {
+ DBG4(DBG_IKE, "PPK %B", &ppk);
+ if (!derive_skp_ppk(this, ppk, skp, &skp_ppk))
+ {
+ return FALSE;
+ }
+ skp = skp_ppk;
+ }
chunk = chunk_alloca(4);
chunk.ptr[0] = id->get_type(id);
@@ -650,8 +747,10 @@ METHOD(keymat_v2_t, get_auth_octets, bool,
if (!this->prf->set_key(this->prf, skp) ||
!this->prf->allocate_bytes(this->prf, idx, &chunk))
{
+ chunk_clear(&skp_ppk);
return FALSE;
}
+ chunk_clear(&skp_ppk);
*octets = chunk_cat("ccm", ike_sa_init, nonce, chunk);
DBG3(DBG_IKE, "octets = message + nonce + prf(Sk_px, IDx') %B", octets);
return TRUE;
@@ -665,41 +764,53 @@ METHOD(keymat_v2_t, get_auth_octets, bool,
METHOD(keymat_v2_t, get_psk_sig, bool,
private_keymat_v2_t *this, bool verify, chunk_t ike_sa_init, chunk_t nonce,
- chunk_t secret, identification_t *id, char reserved[3], chunk_t *sig)
+ chunk_t secret, chunk_t ppk, identification_t *id, char reserved[3],
+ chunk_t *sig)
{
- chunk_t key_pad, key, octets;
+ chunk_t skp_ppk = chunk_empty, key = chunk_empty, octets = chunk_empty;
+ chunk_t key_pad;
+ bool success = FALSE;
if (!secret.len)
{ /* EAP uses SK_p if no MSK has been established */
secret = verify ? this->skp_verify : this->skp_build;
+ if (ppk.ptr)
+ {
+ if (!derive_skp_ppk(this, ppk, secret, &skp_ppk))
+ {
+ return FALSE;
+ }
+ secret = skp_ppk;
+ }
}
- if (!get_auth_octets(this, verify, ike_sa_init, nonce, id, reserved,
+ if (!get_auth_octets(this, verify, ike_sa_init, nonce, ppk, id, reserved,
&octets, NULL))
{
- return FALSE;
+ goto failure;
}
/* AUTH = prf(prf(Shared Secret,"Key Pad for IKEv2"), <msg octets>) */
key_pad = chunk_create(IKEV2_KEY_PAD, IKEV2_KEY_PAD_LENGTH);
if (!this->prf->set_key(this->prf, secret) ||
!this->prf->allocate_bytes(this->prf, key_pad, &key))
{
- chunk_free(&octets);
- return FALSE;
+ goto failure;
}
if (!this->prf->set_key(this->prf, key) ||
!this->prf->allocate_bytes(this->prf, octets, sig))
{
- chunk_free(&key);
- chunk_free(&octets);
- return FALSE;
+ goto failure;
}
DBG4(DBG_IKE, "secret %B", &secret);
DBG4(DBG_IKE, "prf(secret, keypad) %B", &key);
DBG3(DBG_IKE, "AUTH = prf(prf(secret, keypad), octets) %B", sig);
+ success = TRUE;
+
+failure:
+ chunk_clear(&skp_ppk);
chunk_free(&octets);
chunk_free(&key);
+ return success;
- return TRUE;
}
METHOD(keymat_v2_t, hash_algorithm_supported, bool,
@@ -752,6 +863,7 @@ keymat_v2_t *keymat_v2_create(bool initiator)
.destroy = _destroy,
},
.derive_ike_keys = _derive_ike_keys,
+ .derive_ike_keys_ppk = _derive_ike_keys_ppk,
.derive_child_keys = _derive_child_keys,
.get_skd = _get_skd,
.get_auth_octets = _get_auth_octets,
diff --git a/src/libcharon/sa/ikev2/keymat_v2.h b/src/libcharon/sa/ikev2/keymat_v2.h
index 5dc9cda38..3cc071aeb 100644
--- a/src/libcharon/sa/ikev2/keymat_v2.h
+++ b/src/libcharon/sa/ikev2/keymat_v2.h
@@ -58,6 +58,16 @@ struct keymat_v2_t {
chunk_t rekey_skd);
/**
+ * Derive SK_d, SK_pi and SK_pr after authentication using the given
+ * Postquantum Preshared Key and the previous values of these keys that
+ * were derived by derive_ike_keys().
+ *
+ * @param ppk the postquantum preshared key
+ * @return TRUE on success
+ */
+ bool (*derive_ike_keys_ppk)(keymat_v2_t *this, chunk_t ppk);
+
+ /**
* Derive keys for a CHILD_SA.
*
* The keys for the CHILD_SA are allocated in the integ and encr chunks.
@@ -95,9 +105,10 @@ struct keymat_v2_t {
* key. PSK and EAP authentication include a secret into the data, use
* the get_psk_sig() method instead.
*
- * @param verify TRUE to create for verfification, FALSE to sign
+ * @param verify TRUE to create for verification, FALSE to sign
* @param ike_sa_init encoded ike_sa_init message
* @param nonce nonce value
+ * @param ppk optional postquantum preshared key
* @param id identity
* @param reserved reserved bytes of id_payload
* @param octests chunk receiving allocated auth octets
@@ -107,7 +118,7 @@ struct keymat_v2_t {
* @return TRUE if octets created successfully
*/
bool (*get_auth_octets)(keymat_v2_t *this, bool verify, chunk_t ike_sa_init,
- chunk_t nonce, identification_t *id,
+ chunk_t nonce, chunk_t ppk, identification_t *id,
char reserved[3], chunk_t *octets,
array_t *schemes);
/**
@@ -117,17 +128,18 @@ struct keymat_v2_t {
* includes the secret into the signature. If no secret is given, SK_p is
* used as secret (used for EAP methods without MSK).
*
- * @param verify TRUE to create for verfification, FALSE to sign
+ * @param verify TRUE to create for verification, FALSE to sign
* @param ike_sa_init encoded ike_sa_init message
* @param nonce nonce value
* @param secret optional secret to include into signature
+ * @param ppk optional postquantum preshared key
* @param id identity
* @param reserved reserved bytes of id_payload
* @param sign chunk receiving allocated signature octets
* @return TRUE if signature created successfully
*/
bool (*get_psk_sig)(keymat_v2_t *this, bool verify, chunk_t ike_sa_init,
- chunk_t nonce, chunk_t secret,
+ chunk_t nonce, chunk_t secret, chunk_t ppk,
identification_t *id, char reserved[3], chunk_t *sig);
/**
diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c
index fff567233..910c77a2d 100644
--- a/src/libcharon/sa/ikev2/task_manager_v2.c
+++ b/src/libcharon/sa/ikev2/task_manager_v2.c
@@ -109,7 +109,7 @@ struct private_task_manager_t {
array_t *packets;
/**
- * type of the initated exchange
+ * type of the initiated exchange
*/
exchange_type_t type;
@@ -1946,8 +1946,7 @@ METHOD(task_manager_t, queue_dpd, void,
{
ike_mobike_t *mobike;
- if (this->ike_sa->supports_extension(this->ike_sa, EXT_MOBIKE) &&
- this->ike_sa->has_condition(this->ike_sa, COND_NAT_HERE))
+ if (this->ike_sa->supports_extension(this->ike_sa, EXT_MOBIKE))
{
#ifdef ME
peer_cfg_t *cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
diff --git a/src/libcharon/sa/ikev2/tasks/child_create.c b/src/libcharon/sa/ikev2/tasks/child_create.c
index c90af23b9..c7eb0c854 100644
--- a/src/libcharon/sa/ikev2/tasks/child_create.c
+++ b/src/libcharon/sa/ikev2/tasks/child_create.c
@@ -481,12 +481,14 @@ static linked_list_t* narrow_ts(private_child_create_t *this, bool local,
this->ike_sa->has_condition(this->ike_sa, cond))
{
nat = get_transport_nat_ts(this, local, in);
- ts = this->config->get_traffic_selectors(this->config, local, nat, hosts);
+ ts = this->config->get_traffic_selectors(this->config, local, nat,
+ hosts, TRUE);
nat->destroy_offset(nat, offsetof(traffic_selector_t, destroy));
}
else
{
- ts = this->config->get_traffic_selectors(this->config, local, in, hosts);
+ ts = this->config->get_traffic_selectors(this->config, local, in,
+ hosts, TRUE);
}
hosts->destroy(hosts);
@@ -497,8 +499,8 @@ static linked_list_t* narrow_ts(private_child_create_t *this, bool local,
/**
* Install a CHILD_SA for usage, return value:
* - FAILED: no acceptable proposal
- * - INVALID_ARG: diffie hellman group inacceptable
- * - NOT_FOUND: TS inacceptable
+ * - INVALID_ARG: diffie hellman group unacceptable
+ * - NOT_FOUND: TS unacceptable
*/
static status_t select_and_install(private_child_create_t *this,
bool no_dh, bool ike_auth)
@@ -559,7 +561,7 @@ static status_t select_and_install(private_child_create_t *this,
if (this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP,
&group, NULL))
{
- DBG1(DBG_IKE, "DH group %N inacceptable, requesting %N",
+ DBG1(DBG_IKE, "DH group %N unacceptable, requesting %N",
diffie_hellman_group_names, this->dh_group,
diffie_hellman_group_names, group);
this->dh_group = group;
@@ -1075,7 +1077,7 @@ METHOD(task_t, build_i, status_t,
if (list->get_count(list))
{
this->tsi = this->config->get_traffic_selectors(this->config,
- TRUE, NULL, list);
+ TRUE, NULL, list, TRUE);
list->destroy_offset(list, offsetof(host_t, destroy));
}
else
@@ -1083,12 +1085,12 @@ METHOD(task_t, build_i, status_t,
list->destroy(list);
list = get_dynamic_hosts(this->ike_sa, TRUE);
this->tsi = this->config->get_traffic_selectors(this->config,
- TRUE, NULL, list);
+ TRUE, NULL, list, TRUE);
list->destroy(list);
}
list = get_dynamic_hosts(this->ike_sa, FALSE);
this->tsr = this->config->get_traffic_selectors(this->config,
- FALSE, NULL, list);
+ FALSE, NULL, list, TRUE);
list->destroy(list);
if (this->packet_tsi)
@@ -1356,7 +1358,7 @@ METHOD(task_t, build_r, status_t,
}
if (this->config == NULL)
{
- DBG1(DBG_IKE, "traffic selectors %#R === %#R inacceptable",
+ DBG1(DBG_IKE, "traffic selectors %#R === %#R unacceptable",
this->tsr, this->tsi);
charon->bus->alert(charon->bus, ALERT_TS_MISMATCH, this->tsi, this->tsr);
message->add_notify(message, FALSE, TS_UNACCEPTABLE, chunk_empty);
diff --git a/src/libcharon/sa/ikev2/tasks/ike_auth.c b/src/libcharon/sa/ikev2/tasks/ike_auth.c
index 6b63197d5..b055ff064 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-2015 Tobias Brunner
+ * Copyright (C) 2012-2018 Tobias Brunner
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2005 Jan Hutter
* HSR Hochschule fuer Technik Rapperswil
@@ -24,6 +24,7 @@
#include <encoding/payloads/auth_payload.h>
#include <encoding/payloads/eap_payload.h>
#include <encoding/payloads/nonce_payload.h>
+#include <sa/ikev2/keymat_v2.h>
#include <sa/ikev2/authenticators/eap_authenticator.h>
#include <processing/jobs/delete_ike_sa_job.h>
@@ -60,6 +61,16 @@ struct private_ike_auth_t {
chunk_t other_nonce;
/**
+ * PPK_ID sent or received
+ */
+ identification_t *ppk_id;
+
+ /**
+ * Optional PPK to use
+ */
+ chunk_t ppk;
+
+ /**
* IKE_SA_INIT message sent by us
*/
packet_t *my_packet;
@@ -144,7 +155,7 @@ static status_t collect_my_init_data(private_ike_auth_t *this,
/* get the nonce that was generated in ike_init */
nonce = (nonce_payload_t*)message->get_payload(message, PLV2_NONCE);
- if (nonce == NULL)
+ if (!nonce)
{
return FAILED;
}
@@ -170,7 +181,7 @@ static status_t collect_other_init_data(private_ike_auth_t *this,
/* get the nonce that was generated in ike_init */
nonce = (nonce_payload_t*)message->get_payload(message, PLV2_NONCE);
- if (nonce == NULL)
+ if (!nonce)
{
return FAILED;
}
@@ -279,19 +290,47 @@ static bool do_another_auth(private_ike_auth_t *this)
}
/**
+ * Check if this is the first authentication round
+ */
+static bool is_first_round(private_ike_auth_t *this, bool local)
+{
+ enumerator_t *done;
+ auth_cfg_t *cfg;
+
+ if (!this->ike_sa->supports_extension(this->ike_sa, EXT_MULTIPLE_AUTH))
+ {
+ return TRUE;
+ }
+
+ done = this->ike_sa->create_auth_cfg_enumerator(this->ike_sa, local);
+ if (done->enumerate(done, &cfg))
+ {
+ done->destroy(done);
+ return FALSE;
+ }
+ done->destroy(done);
+ return TRUE;
+}
+
+/**
* Get peer configuration candidates from backends
*/
static bool load_cfg_candidates(private_ike_auth_t *this)
{
enumerator_t *enumerator;
peer_cfg_t *peer_cfg;
+ ike_cfg_t *ike_cfg;
host_t *me, *other;
identification_t *my_id, *other_id;
+ proposal_t *ike_proposal;
+ bool private;
me = this->ike_sa->get_my_host(this->ike_sa);
other = this->ike_sa->get_other_host(this->ike_sa);
my_id = this->ike_sa->get_my_id(this->ike_sa);
other_id = this->ike_sa->get_other_id(this->ike_sa);
+ ike_proposal = this->ike_sa->get_proposal(this->ike_sa);
+ private = this->ike_sa->supports_extension(this->ike_sa, EXT_STRONGSWAN);
DBG1(DBG_CFG, "looking for peer configs matching %H[%Y]...%H[%Y]",
me, my_id, other, other_id);
@@ -299,11 +338,18 @@ static bool load_cfg_candidates(private_ike_auth_t *this)
me, other, my_id, other_id, IKEV2);
while (enumerator->enumerate(enumerator, &peer_cfg))
{
+ /* ignore all configs that have no matching IKE proposal */
+ ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
+ if (!ike_cfg->has_proposal(ike_cfg, ike_proposal, private))
+ {
+ DBG2(DBG_CFG, "ignore candidate '%s' without matching IKE proposal",
+ peer_cfg->get_name(peer_cfg));
+ continue;
+ }
peer_cfg->get_ref(peer_cfg);
- if (this->peer_cfg == NULL)
+ if (!this->peer_cfg)
{ /* best match */
this->peer_cfg = peer_cfg;
- this->ike_sa->set_peer_cfg(this->ike_sa, peer_cfg);
}
else
{
@@ -313,6 +359,7 @@ static bool load_cfg_candidates(private_ike_auth_t *this)
enumerator->destroy(enumerator);
if (this->peer_cfg)
{
+ this->ike_sa->set_peer_cfg(this->ike_sa, this->peer_cfg);
DBG1(DBG_CFG, "selected peer config '%s'",
this->peer_cfg->get_name(this->peer_cfg));
return TRUE;
@@ -369,7 +416,7 @@ static bool update_cfg_candidates(private_ike_auth_t *this, bool strict)
{
break;
}
- DBG1(DBG_CFG, "selected peer config '%s' inacceptable: %s",
+ DBG1(DBG_CFG, "selected peer config '%s' unacceptable: %s",
this->peer_cfg->get_name(this->peer_cfg), comply_error);
this->peer_cfg->destroy(this->peer_cfg);
}
@@ -391,6 +438,149 @@ static bool update_cfg_candidates(private_ike_auth_t *this, bool strict)
return this->peer_cfg != NULL;
}
+/**
+ * Currently defined PPK_ID types
+ */
+#define PPK_ID_OPAQUE 1
+#define PPK_ID_FIXED 2
+
+/**
+ * Parse the payload data of the given PPK_IDENTITY notify
+ */
+static bool parse_ppk_identity(notify_payload_t *notify, identification_t **id)
+{
+ chunk_t data;
+
+ data = notify->get_notification_data(notify);
+ if (data.len < 2)
+ {
+ return FALSE;
+ }
+ switch (data.ptr[0])
+ {
+ case PPK_ID_FIXED:
+ data = chunk_skip(data, 1);
+ break;
+ default:
+ return FALSE;
+ }
+ *id = identification_create_from_data(data);
+ return TRUE;
+}
+
+/**
+ * Add a PPK_IDENTITY with the given PPK_ID to the given message
+ */
+static void add_ppk_identity(identification_t *id, message_t *msg)
+{
+ chunk_t data;
+ uint8_t type = PPK_ID_FIXED;
+
+ /* we currently only support one type */
+ data = chunk_cata("cc", chunk_from_thing(type), id->get_encoding(id));
+ msg->add_notify(msg, FALSE, PPK_IDENTITY, data);
+}
+
+/**
+ * Use the given PPK_ID to find a PPK and store it and the ID in the task
+ */
+static bool get_ppk(private_ike_auth_t *this, identification_t *ppk_id)
+{
+ shared_key_t *key;
+
+ key = lib->credmgr->get_shared(lib->credmgr, SHARED_PPK, ppk_id, NULL);
+ if (!key)
+ {
+ if (this->peer_cfg->ppk_required(this->peer_cfg))
+ {
+ DBG1(DBG_CFG, "PPK required but no PPK found for '%Y'", ppk_id);
+ return FALSE;
+ }
+ DBG1(DBG_CFG, "no PPK for '%Y' found, ignored because PPK is not "
+ "required", ppk_id);
+ return TRUE;
+ }
+ this->ppk = chunk_clone(key->get_key(key));
+ this->ppk_id = ppk_id->clone(ppk_id);
+ key->destroy(key);
+ return TRUE;
+}
+
+/**
+ * Check if we have a PPK available and, if not, whether we require one as
+ * initiator
+ */
+static bool get_ppk_i(private_ike_auth_t *this)
+{
+ identification_t *ppk_id;
+
+ if (!this->ike_sa->supports_extension(this->ike_sa, EXT_PPK))
+ {
+ if (this->peer_cfg->ppk_required(this->peer_cfg))
+ {
+ DBG1(DBG_CFG, "PPK required but peer does not support PPK");
+ return FALSE;
+ }
+ return TRUE;
+ }
+
+ ppk_id = this->peer_cfg->get_ppk_id(this->peer_cfg);
+ if (!ppk_id)
+ {
+ if (this->peer_cfg->ppk_required(this->peer_cfg))
+ {
+ DBG1(DBG_CFG, "PPK required but no PPK_ID configured");
+ return FALSE;
+ }
+ return TRUE;
+ }
+ return get_ppk(this, ppk_id);
+}
+
+/**
+ * Check if we have a PPK available and if not whether we require one as
+ * responder
+ */
+static bool get_ppk_r(private_ike_auth_t *this, message_t *msg)
+{
+ notify_payload_t *notify;
+ identification_t *ppk_id, *ppk_id_cfg;
+ bool result;
+
+ if (!this->ike_sa->supports_extension(this->ike_sa, EXT_PPK))
+ {
+ if (this->peer_cfg->ppk_required(this->peer_cfg))
+ {
+ DBG1(DBG_CFG, "PPK required but peer does not support PPK");
+ return FALSE;
+ }
+ return TRUE;
+ }
+
+ notify = msg->get_notify(msg, PPK_IDENTITY);
+ if (!notify || !parse_ppk_identity(notify, &ppk_id))
+ {
+ if (this->peer_cfg->ppk_required(this->peer_cfg))
+ {
+ DBG1(DBG_CFG, "PPK required but no PPK_IDENTITY received");
+ return FALSE;
+ }
+ return TRUE;
+ }
+
+ ppk_id_cfg = this->peer_cfg->get_ppk_id(this->peer_cfg);
+ if (ppk_id_cfg && !ppk_id->matches(ppk_id, ppk_id_cfg))
+ {
+ DBG1(DBG_CFG, "received PPK_ID '%Y', but require '%Y'", ppk_id,
+ ppk_id_cfg);
+ ppk_id->destroy(ppk_id);
+ return FALSE;
+ }
+ result = get_ppk(this, ppk_id);
+ ppk_id->destroy(ppk_id);
+ return result;
+}
+
METHOD(task_t, build_i, status_t,
private_ike_auth_t *this, message_t *message)
{
@@ -401,7 +591,7 @@ METHOD(task_t, build_i, status_t,
return collect_my_init_data(this, message);
}
- if (this->peer_cfg == NULL)
+ if (!this->peer_cfg)
{
this->peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
this->peer_cfg->get_ref(this->peer_cfg);
@@ -420,6 +610,12 @@ METHOD(task_t, build_i, status_t,
/* indicate support for RFC 6311 Message ID synchronization */
message->add_notify(message, FALSE, IKEV2_MESSAGE_ID_SYNC_SUPPORTED,
chunk_empty);
+ /* only use a PPK in the first round */
+ if (!get_ppk_i(this))
+ {
+ charon->bus->alert(charon->bus, ALERT_LOCAL_AUTH_FAILED);
+ return FAILED;
+ }
}
if (!this->do_another_auth && !this->my_auth)
@@ -428,7 +624,7 @@ METHOD(task_t, build_i, status_t,
}
/* check if an authenticator is in progress */
- if (this->my_auth == NULL)
+ if (!this->my_auth)
{
identification_t *idi, *idr = NULL;
id_payload_t *id_payload;
@@ -495,6 +691,14 @@ METHOD(task_t, build_i, status_t,
return FAILED;
}
}
+ /* for authentication methods that return NEED_MORE, the PPK will be reset
+ * in process_i() for messages without PPK_ID notify, so we always set it
+ * during the first round (afterwards the PPK won't be available) */
+ if (this->ppk.ptr && this->my_auth->use_ppk)
+ {
+ this->my_auth->use_ppk(this->my_auth, this->ppk,
+ !this->peer_cfg->ppk_required(this->peer_cfg));
+ }
switch (this->my_auth->build(this->my_auth, message))
{
case SUCCESS:
@@ -509,6 +713,12 @@ METHOD(task_t, build_i, status_t,
return FAILED;
}
+ /* add a PPK_IDENTITY notify to the message that contains AUTH */
+ if (this->ppk_id && message->get_payload(message, PLV2_AUTH))
+ {
+ add_ppk_identity(this->ppk_id, message);
+ }
+
/* check for additional authentication rounds */
if (do_another_auth(this))
{
@@ -536,7 +746,7 @@ METHOD(task_t, process_r, status_t,
return collect_other_init_data(this, message);
}
- if (this->my_auth == NULL && this->do_another_auth)
+ if (!this->my_auth && this->do_another_auth)
{
/* handle (optional) IDr payload, apply proposed identity */
id_payload = (id_payload_t*)message->get_payload(message, PLV2_ID_RESPONDER);
@@ -573,7 +783,7 @@ METHOD(task_t, process_r, status_t,
}
}
- if (this->other_auth == NULL)
+ if (!this->other_auth)
{
/* handle IDi payload */
id_payload = (id_payload_t*)message->get_payload(message, PLV2_ID_INITIATOR);
@@ -588,7 +798,7 @@ METHOD(task_t, process_r, status_t,
cfg = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
cfg->add(cfg, AUTH_RULE_IDENTITY, id->clone(id));
- if (this->peer_cfg == NULL)
+ if (!this->peer_cfg)
{
if (!load_cfg_candidates(this))
{
@@ -596,14 +806,14 @@ METHOD(task_t, process_r, status_t,
return NEED_MORE;
}
}
- if (message->get_payload(message, PLV2_AUTH) == NULL)
+ if (!message->get_payload(message, PLV2_AUTH))
{ /* before authenticating with EAP, we need a EAP config */
cand = get_auth_cfg(this, FALSE);
while (!cand || (
(uintptr_t)cand->get(cand, AUTH_RULE_EAP_TYPE) == EAP_NAK &&
(uintptr_t)cand->get(cand, AUTH_RULE_EAP_VENDOR) == 0))
{ /* peer requested EAP, but current config does not match */
- DBG1(DBG_IKE, "peer requested EAP, config inacceptable");
+ DBG1(DBG_IKE, "peer requested EAP, config unacceptable");
this->peer_cfg->destroy(this->peer_cfg);
this->peer_cfg = NULL;
if (!update_cfg_candidates(this, FALSE))
@@ -642,6 +852,19 @@ METHOD(task_t, process_r, status_t,
return NEED_MORE;
}
}
+ if (message->get_payload(message, PLV2_AUTH) &&
+ is_first_round(this, FALSE))
+ {
+ if (!get_ppk_r(this, message))
+ {
+ this->authentication_failed = TRUE;
+ return NEED_MORE;
+ }
+ else if (this->ppk.ptr && this->other_auth->use_ppk)
+ {
+ this->other_auth->use_ppk(this->other_auth, this->ppk, FALSE);
+ }
+ }
switch (this->other_auth->process(this->other_auth, message))
{
case SUCCESS:
@@ -675,7 +898,7 @@ METHOD(task_t, process_r, status_t,
return NEED_MORE;
}
- if (message->get_notify(message, ANOTHER_AUTH_FOLLOWS) == NULL)
+ if (!message->get_notify(message, ANOTHER_AUTH_FOLLOWS))
{
this->expect_another_auth = FALSE;
if (!update_cfg_candidates(this, TRUE))
@@ -687,6 +910,37 @@ METHOD(task_t, process_r, status_t,
return NEED_MORE;
}
+/**
+ * Clear the PPK and PPK_ID
+ */
+static void clear_ppk(private_ike_auth_t *this)
+{
+ DESTROY_IF(this->ppk_id);
+ this->ppk_id = NULL;
+ chunk_clear(&this->ppk);
+}
+
+/**
+ * Derive new keys and clear the PPK
+ */
+static bool apply_ppk(private_ike_auth_t *this)
+{
+ keymat_v2_t *keymat;
+
+ if (this->ppk.ptr)
+ {
+ keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa);
+ if (!keymat->derive_ike_keys_ppk(keymat, this->ppk))
+ {
+ return FALSE;
+ }
+ DBG1(DBG_CFG, "using PPK for PPK_ID '%Y'", this->ppk_id);
+ this->ike_sa->set_condition(this->ike_sa, COND_PPK, TRUE);
+ }
+ clear_ppk(this);
+ return TRUE;
+}
+
METHOD(task_t, build_r, status_t,
private_ike_auth_t *this, message_t *message)
{
@@ -703,12 +957,12 @@ METHOD(task_t, build_r, status_t,
return collect_my_init_data(this, message);
}
- if (this->authentication_failed || this->peer_cfg == NULL)
+ if (this->authentication_failed || !this->peer_cfg)
{
goto peer_auth_failed;
}
- if (this->my_auth == NULL && this->do_another_auth)
+ if (!this->my_auth && this->do_another_auth)
{
identification_t *id, *id_cfg;
id_payload_t *id_payload;
@@ -793,6 +1047,10 @@ METHOD(task_t, build_r, status_t,
}
if (this->my_auth)
{
+ if (this->ppk.ptr && this->my_auth->use_ppk)
+ {
+ this->my_auth->use_ppk(this->my_auth, this->ppk, FALSE);
+ }
switch (this->my_auth->build(this->my_auth, message))
{
case SUCCESS:
@@ -807,6 +1065,16 @@ METHOD(task_t, build_r, status_t,
}
}
+ /* add a PPK_IDENTITY notify and derive new keys and clear the PPK */
+ if (this->ppk.ptr)
+ {
+ message->add_notify(message, FALSE, PPK_IDENTITY, chunk_empty);
+ if (!apply_ppk(this))
+ {
+ goto local_auth_failed;
+ }
+ }
+
/* check for additional authentication rounds */
if (do_another_auth(this))
{
@@ -942,7 +1210,7 @@ METHOD(task_t, process_i, status_t,
enumerator_t *enumerator;
payload_t *payload;
auth_cfg_t *cfg;
- bool mutual_eap = FALSE;
+ bool mutual_eap = FALSE, ppk_id_received = FALSE;
if (message->get_exchange_type(message) == IKE_SA_INIT)
{
@@ -998,6 +1266,9 @@ METHOD(task_t, process_i, status_t,
this->ike_sa->enable_extension(this->ike_sa,
EXT_IKE_MESSAGE_ID_SYNC);
break;
+ case PPK_IDENTITY:
+ ppk_id_received = TRUE;
+ break;
default:
{
if (type <= 16383)
@@ -1019,7 +1290,7 @@ METHOD(task_t, process_i, status_t,
if (this->expect_another_auth)
{
- if (this->other_auth == NULL)
+ if (!this->other_auth)
{
id_payload_t *id_payload;
identification_t *id;
@@ -1059,6 +1330,11 @@ METHOD(task_t, process_i, status_t,
}
if (this->other_auth)
{
+ if (ppk_id_received && is_first_round(this, FALSE) &&
+ this->other_auth->use_ppk)
+ {
+ this->other_auth->use_ppk(this->other_auth, this->ppk, FALSE);
+ }
switch (this->other_auth->process(this->other_auth, message))
{
case SUCCESS:
@@ -1094,6 +1370,14 @@ METHOD(task_t, process_i, status_t,
if (this->my_auth)
{
+ /* while we already set the PPK in build_i(), we MUST not use it if
+ * the peer did not reply with a PPK_ID notify */
+ if (this->ppk.ptr && this->my_auth->use_ppk)
+ {
+ this->my_auth->use_ppk(this->my_auth,
+ ppk_id_received ? this->ppk : chunk_empty,
+ FALSE);
+ }
switch (this->my_auth->process(this->my_auth, message))
{
case SUCCESS:
@@ -1109,11 +1393,29 @@ METHOD(task_t, process_i, status_t,
case NEED_MORE:
break;
default:
- charon->bus->alert(charon->bus, ALERT_LOCAL_AUTH_FAILED);
- send_auth_failed_informational(this, message);
- return FAILED;
+ goto local_auth_failed;
+ }
+ }
+
+ /* change keys and clear PPK after we are done with our authentication, so
+ * we only explicitly use it for the first round, afterwards we just use the
+ * changed SK_p keys implicitly */
+ if (!this->my_auth && this->ppk_id)
+ {
+ if (ppk_id_received)
+ {
+ if (!apply_ppk(this))
+ {
+ goto local_auth_failed;
+ }
+ }
+ else
+ {
+ DBG1(DBG_CFG, "peer didn't use PPK for PPK_ID '%Y'", this->ppk_id);
}
+ clear_ppk(this);
}
+
if (mutual_eap)
{
if (!this->my_auth || !this->my_auth->is_mutual(this->my_auth))
@@ -1124,7 +1426,7 @@ METHOD(task_t, process_i, status_t,
DBG1(DBG_IKE, "allow mutual EAP-only authentication");
}
- if (message->get_notify(message, ANOTHER_AUTH_FOLLOWS) == NULL)
+ if (!message->get_notify(message, ANOTHER_AUTH_FOLLOWS))
{
this->expect_another_auth = FALSE;
}
@@ -1162,6 +1464,10 @@ peer_auth_failed:
charon->bus->alert(charon->bus, ALERT_PEER_AUTH_FAILED);
send_auth_failed_informational(this, message);
return FAILED;
+local_auth_failed:
+ charon->bus->alert(charon->bus, ALERT_LOCAL_AUTH_FAILED);
+ send_auth_failed_informational(this, message);
+ return FAILED;
}
METHOD(task_t, get_type, task_type_t,
@@ -1173,6 +1479,7 @@ METHOD(task_t, get_type, task_type_t,
METHOD(task_t, migrate, void,
private_ike_auth_t *this, ike_sa_t *ike_sa)
{
+ clear_ppk(this);
chunk_free(&this->my_nonce);
chunk_free(&this->other_nonce);
DESTROY_IF(this->my_packet);
@@ -1199,6 +1506,7 @@ METHOD(task_t, migrate, void,
METHOD(task_t, destroy, void,
private_ike_auth_t *this)
{
+ clear_ppk(this);
chunk_free(&this->my_nonce);
chunk_free(&this->other_nonce);
DESTROY_IF(this->my_packet);
diff --git a/src/libcharon/sa/ikev2/tasks/ike_auth_lifetime.h b/src/libcharon/sa/ikev2/tasks/ike_auth_lifetime.h
index f6862ca27..fd14e9faf 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_auth_lifetime.h
+++ b/src/libcharon/sa/ikev2/tasks/ike_auth_lifetime.h
@@ -45,7 +45,7 @@ struct ike_auth_lifetime_t {
* Create a new TASK_IKE_AUTH_LIFETIME task.
*
* @param ike_sa IKE_SA this task works for
- * @param initiator TRUE if taks is initiated by us
+ * @param initiator TRUE if task is initiated by us
* @return ike_auth_lifetime task to handle by the task_manager
*/
ike_auth_lifetime_t *ike_auth_lifetime_create(ike_sa_t *ike_sa, bool initiator);
diff --git a/src/libcharon/sa/ikev2/tasks/ike_init.c b/src/libcharon/sa/ikev2/tasks/ike_init.c
index 3d73d728b..307d99264 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_init.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_init.c
@@ -55,11 +55,6 @@ struct private_ike_init_t {
bool initiator;
/**
- * IKE config to establish
- */
- ike_cfg_t *config;
-
- /**
* diffie hellman group to use
*/
diffie_hellman_group_t dh_group;
@@ -275,6 +270,38 @@ static void handle_supported_hash_algorithms(private_ike_init_t *this,
}
/**
+ * Check whether to send a USE_PPK notify
+ */
+static bool send_use_ppk(private_ike_init_t *this)
+{
+ peer_cfg_t *peer;
+ enumerator_t *keys;
+ shared_key_t *key;
+ bool use_ppk = FALSE;
+
+ if (this->initiator)
+ {
+ peer = this->ike_sa->get_peer_cfg(this->ike_sa);
+ if (peer->get_ppk_id(peer))
+ {
+ use_ppk = TRUE;
+ }
+ }
+ else if (this->ike_sa->supports_extension(this->ike_sa, EXT_PPK))
+ {
+ /* check if we have at least one PPK available */
+ keys = lib->credmgr->create_shared_enumerator(lib->credmgr, SHARED_PPK,
+ NULL, NULL);
+ if (keys->enumerate(keys, &key, NULL, NULL))
+ {
+ use_ppk = TRUE;
+ }
+ keys->destroy(keys);
+ }
+ return use_ppk;
+}
+
+/**
* build the payloads for the message
*/
static bool build_payloads(private_ike_init_t *this, message_t *message)
@@ -286,14 +313,15 @@ static bool build_payloads(private_ike_init_t *this, message_t *message)
ike_sa_id_t *id;
proposal_t *proposal;
enumerator_t *enumerator;
+ ike_cfg_t *ike_cfg;
id = this->ike_sa->get_id(this->ike_sa);
- this->config = this->ike_sa->get_ike_cfg(this->ike_sa);
+ ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
if (this->initiator)
{
- proposal_list = this->config->get_proposals(this->config);
+ proposal_list = ike_cfg->get_proposals(ike_cfg);
other_dh_groups = linked_list_create();
enumerator = proposal_list->create_enumerator(proposal_list);
while (enumerator->enumerate(enumerator, (void**)&proposal))
@@ -334,8 +362,6 @@ static bool build_payloads(private_ike_init_t *this, message_t *message)
}
message->add_payload(message, (payload_t*)sa_payload);
- nonce_payload = nonce_payload_create(PLV2_NONCE);
- nonce_payload->set_nonce(nonce_payload, this->my_nonce);
ke_payload = ke_payload_create_from_diffie_hellman(PLV2_KEY_EXCHANGE,
this->dh);
if (!ke_payload)
@@ -343,6 +369,8 @@ static bool build_payloads(private_ike_init_t *this, message_t *message)
DBG1(DBG_IKE, "creating KE payload failed");
return FALSE;
}
+ nonce_payload = nonce_payload_create(PLV2_NONCE);
+ nonce_payload->set_nonce(nonce_payload, this->my_nonce);
if (this->old_sa)
{ /* payload order differs if we are rekeying */
@@ -357,7 +385,7 @@ static bool build_payloads(private_ike_init_t *this, message_t *message)
/* negotiate fragmentation if we are not rekeying */
if (!this->old_sa &&
- this->config->fragmentation(this->config) != FRAGMENTATION_NO)
+ ike_cfg->fragmentation(ike_cfg) != FRAGMENTATION_NO)
{
if (this->initiator ||
this->ike_sa->supports_extension(this->ike_sa,
@@ -400,10 +428,77 @@ static bool build_payloads(private_ike_init_t *this, message_t *message)
chunk_empty);
}
}
+ /* notify the peer if we want to use/support PPK */
+ if (!this->old_sa && send_use_ppk(this))
+ {
+ message->add_notify(message, FALSE, USE_PPK, chunk_empty);
+ }
return TRUE;
}
/**
+ * Process the SA payload and select a proposal
+ */
+static void process_sa_payload(private_ike_init_t *this, message_t *message,
+ sa_payload_t *sa_payload)
+{
+ ike_cfg_t *ike_cfg, *cfg, *alt_cfg = NULL;
+ enumerator_t *enumerator;
+ linked_list_t *proposal_list;
+ host_t *me, *other;
+ bool private, prefer_configured;
+
+ ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
+
+ proposal_list = sa_payload->get_proposals(sa_payload);
+ private = this->ike_sa->supports_extension(this->ike_sa, EXT_STRONGSWAN);
+ prefer_configured = lib->settings->get_bool(lib->settings,
+ "%s.prefer_configured_proposals", TRUE, lib->ns);
+
+ this->proposal = ike_cfg->select_proposal(ike_cfg, proposal_list, private,
+ prefer_configured);
+ if (!this->proposal)
+ {
+ if (!this->initiator && !this->old_sa)
+ {
+ me = message->get_destination(message);
+ other = message->get_source(message);
+ enumerator = charon->backends->create_ike_cfg_enumerator(
+ charon->backends, me, other, IKEV2);
+ while (enumerator->enumerate(enumerator, &cfg))
+ {
+ if (ike_cfg == cfg)
+ { /* already tried and failed */
+ continue;
+ }
+ DBG1(DBG_IKE, "no matching proposal found, trying alternative "
+ "config");
+ this->proposal = cfg->select_proposal(cfg, proposal_list,
+ private, prefer_configured);
+ if (this->proposal)
+ {
+ alt_cfg = cfg->get_ref(cfg);
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ }
+ if (alt_cfg)
+ {
+ this->ike_sa->set_ike_cfg(this->ike_sa, alt_cfg);
+ alt_cfg->destroy(alt_cfg);
+ }
+ else
+ {
+ charon->bus->alert(charon->bus, ALERT_PROPOSAL_MISMATCH_IKE,
+ proposal_list);
+ }
+ }
+ proposal_list->destroy_offset(proposal_list,
+ offsetof(proposal_t, destroy));
+}
+
+/**
* Read payloads from message
*/
static void process_payloads(private_ike_init_t *this, message_t *message)
@@ -419,24 +514,7 @@ static void process_payloads(private_ike_init_t *this, message_t *message)
{
case PLV2_SECURITY_ASSOCIATION:
{
- sa_payload_t *sa_payload = (sa_payload_t*)payload;
- linked_list_t *proposal_list;
- bool private, prefer_configured;
-
- proposal_list = sa_payload->get_proposals(sa_payload);
- private = this->ike_sa->supports_extension(this->ike_sa,
- EXT_STRONGSWAN);
- prefer_configured = lib->settings->get_bool(lib->settings,
- "%s.prefer_configured_proposals", TRUE, lib->ns);
- this->proposal = this->config->select_proposal(this->config,
- proposal_list, private, prefer_configured);
- if (!this->proposal)
- {
- charon->bus->alert(charon->bus, ALERT_PROPOSAL_MISMATCH_IKE,
- proposal_list);
- }
- proposal_list->destroy_offset(proposal_list,
- offsetof(proposal_t, destroy));
+ process_sa_payload(this, message, (sa_payload_t*)payload);
break;
}
case PLV2_KEY_EXCHANGE:
@@ -469,6 +547,13 @@ static void process_payloads(private_ike_init_t *this, message_t *message)
handle_supported_hash_algorithms(this, notify);
}
break;
+ case USE_PPK:
+ if (!this->old_sa)
+ {
+ this->ike_sa->enable_extension(this->ike_sa,
+ EXT_PPK);
+ }
+ break;
case REDIRECTED_FROM:
{
identification_t *gateway;
@@ -533,7 +618,10 @@ static void process_payloads(private_ike_init_t *this, message_t *message)
METHOD(task_t, build_i, status_t,
private_ike_init_t *this, message_t *message)
{
- this->config = this->ike_sa->get_ike_cfg(this->ike_sa);
+ ike_cfg_t *ike_cfg;
+
+ ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
+
DBG0(DBG_IKE, "initiating IKE_SA %s[%d] to %H",
this->ike_sa->get_name(this->ike_sa),
this->ike_sa->get_unique_id(this->ike_sa),
@@ -563,12 +651,12 @@ METHOD(task_t, build_i, status_t,
}
else
{ /* this shouldn't happen, but let's be safe */
- this->dh_group = this->config->get_dh_group(this->config);
+ this->dh_group = ike_cfg->get_dh_group(ike_cfg);
}
}
else
{
- this->dh_group = this->config->get_dh_group(this->config);
+ this->dh_group = ike_cfg->get_dh_group(ike_cfg);
}
this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat,
this->dh_group);
@@ -627,7 +715,6 @@ METHOD(task_t, build_i, status_t,
METHOD(task_t, process_r, status_t,
private_ike_init_t *this, message_t *message)
{
- this->config = this->ike_sa->get_ike_cfg(this->ike_sa);
DBG0(DBG_IKE, "%H is initiating an IKE_SA", message->get_source(message));
this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING);
@@ -699,7 +786,7 @@ METHOD(task_t, build_r, status_t,
if (this->proposal == NULL ||
this->other_nonce.len == 0 || this->my_nonce.len == 0)
{
- DBG1(DBG_IKE, "received proposals inacceptable");
+ DBG1(DBG_IKE, "received proposals unacceptable");
message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty);
return FAILED;
}
@@ -728,7 +815,7 @@ METHOD(task_t, build_r, status_t,
if (this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP,
&group, NULL))
{
- DBG1(DBG_IKE, "DH group %N inacceptable, requesting %N",
+ DBG1(DBG_IKE, "DH group %N unacceptable, requesting %N",
diffie_hellman_group_names, this->dh_group,
diffie_hellman_group_names, group);
this->dh_group = group;
@@ -770,12 +857,14 @@ METHOD(task_t, build_r, status_t,
*/
static void raise_alerts(private_ike_init_t *this, notify_type_t type)
{
+ ike_cfg_t *ike_cfg;
linked_list_t *list;
switch (type)
{
case NO_PROPOSAL_CHOSEN:
- list = this->config->get_proposals(this->config);
+ ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
+ list = ike_cfg->get_proposals(ike_cfg);
charon->bus->alert(charon->bus, ALERT_PROPOSAL_MISMATCH_IKE, list);
list->destroy_offset(list, offsetof(proposal_t, destroy));
break;
diff --git a/src/libcharon/sa/ikev2/tasks/ike_mobike.c b/src/libcharon/sa/ikev2/tasks/ike_mobike.c
index fe41a1cac..b2ad0a02a 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_mobike.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_mobike.c
@@ -193,7 +193,7 @@ static void process_payloads(private_ike_mobike_t *this, message_t *message)
case NAT_DETECTION_DESTINATION_IP:
{
/* NAT check in this MOBIKE exchange, create subtask for it */
- if (this->natd == NULL)
+ if (!this->natd)
{
this->natd = ike_natd_create(this->ike_sa, this->initiator);
}
@@ -648,7 +648,7 @@ METHOD(ike_mobike_t, roam, void,
METHOD(ike_mobike_t, dpd, void,
private_ike_mobike_t *this)
{
- if (!this->natd)
+ if (!this->natd && this->ike_sa->has_condition(this->ike_sa, COND_NAT_HERE))
{
this->natd = ike_natd_create(this->ike_sa, this->initiator);
}
diff --git a/src/libcharon/sa/ikev2/tasks/ike_mobike.h b/src/libcharon/sa/ikev2/tasks/ike_mobike.h
index 288b87178..8789ac0af 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_mobike.h
+++ b/src/libcharon/sa/ikev2/tasks/ike_mobike.h
@@ -91,7 +91,7 @@ struct ike_mobike_t {
* Create a new ike_mobike task.
*
* @param ike_sa IKE_SA this task works for
- * @param initiator TRUE if taks is initiated by us
+ * @param initiator TRUE if task is initiated by us
* @return ike_mobike task to handle by the task_manager
*/
ike_mobike_t *ike_mobike_create(ike_sa_t *ike_sa, bool initiator);
diff --git a/src/libcharon/sa/ikev2/tasks/ike_rekey.c b/src/libcharon/sa/ikev2/tasks/ike_rekey.c
index 11123b415..57f9a797e 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_rekey.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_rekey.c
@@ -259,7 +259,7 @@ METHOD(task_t, build_r, status_t,
}
if (this->new_sa == NULL)
{
- /* IKE_SA/a CHILD_SA is in an inacceptable state, deny rekeying */
+ /* IKE_SA/a CHILD_SA is in an unacceptable state, deny rekeying */
message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty);
return SUCCESS;
}
diff --git a/src/libcharon/sa/ikev2/tasks/ike_vendor.c b/src/libcharon/sa/ikev2/tasks/ike_vendor.c
index 8d8969ea0..e81a18a14 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_vendor.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_vendor.c
@@ -59,7 +59,7 @@ struct private_ike_vendor_t {
ike_sa_t *ike_sa;
/**
- * Are we the inititator of this task
+ * Are we the initiator of this task
*/
bool initiator;
};
diff --git a/src/libcharon/sa/shunt_manager.c b/src/libcharon/sa/shunt_manager.c
index a83da0480..d66e70937 100644
--- a/src/libcharon/sa/shunt_manager.c
+++ b/src/libcharon/sa/shunt_manager.c
@@ -117,8 +117,10 @@ static bool install_shunt_policy(child_cfg_t *child)
host_any6 = host_create_any(AF_INET6);
hosts = linked_list_create_with_items(host_any, host_any6, NULL);
- my_ts_list = child->get_traffic_selectors(child, TRUE, NULL, hosts);
- other_ts_list = child->get_traffic_selectors(child, FALSE, NULL, hosts);
+ my_ts_list = child->get_traffic_selectors(child, TRUE, NULL, hosts,
+ FALSE);
+ other_ts_list = child->get_traffic_selectors(child, FALSE, NULL, hosts,
+ FALSE);
hosts->destroy(hosts);
manual_prio = child->get_manual_prio(child);
@@ -287,8 +289,10 @@ static void uninstall_shunt_policy(child_cfg_t *child)
host_any6 = host_create_any(AF_INET6);
hosts = linked_list_create_with_items(host_any, host_any6, NULL);
- my_ts_list = child->get_traffic_selectors(child, TRUE, NULL, hosts);
- other_ts_list = child->get_traffic_selectors(child, FALSE, NULL, hosts);
+ my_ts_list = child->get_traffic_selectors(child, TRUE, NULL, hosts,
+ FALSE);
+ other_ts_list = child->get_traffic_selectors(child, FALSE, NULL, hosts,
+ FALSE);
hosts->destroy(hosts);
manual_prio = child->get_manual_prio(child);
diff --git a/src/libcharon/sa/task.h b/src/libcharon/sa/task.h
index 1a0a1acfa..987ac489d 100644
--- a/src/libcharon/sa/task.h
+++ b/src/libcharon/sa/task.h
@@ -115,7 +115,7 @@ extern enum_name_t *task_type_names;
/**
* Interface for a task, an operation handled within exchanges.
*
- * A task is an elemantary operation. It may be handled by a single or by
+ * A task is an elementary operation. It may be handled by a single or by
* multiple exchanges. An exchange may even complete multiple tasks.
* A task has a build() and an process() operation. The build() operation
* creates payloads and adds it to the message. The process() operation
@@ -128,7 +128,7 @@ extern enum_name_t *task_type_names;
* that the task completed, even when the task completed unsuccessfully. The
* manager then removes the task from the list. A NEED_MORE is returned when
* the task needs further build()/process() calls to complete, the manager
- * leaves the taks in the queue. A returned FAILED indicates a critical failure.
+ * leaves the task in the queue. A returned FAILED indicates a critical failure.
* The manager closes the IKE_SA whenever a task returns FAILED.
*/
struct task_t {
@@ -180,7 +180,7 @@ struct task_t {
* Migrate a task to a new IKE_SA.
*
* After migrating a task, it goes back to a state where it can be
- * used again to initate an exchange. This is useful when a task
+ * used again to initiate an exchange. This is useful when a task
* has to get migrated to a new IKE_SA.
* A special usage is when a INVALID_KE_PAYLOAD is received. A call
* to reset resets the task, but uses another DH group for the next
diff --git a/src/libcharon/sa/trap_manager.c b/src/libcharon/sa/trap_manager.c
index 979f9290a..148df3923 100644
--- a/src/libcharon/sa/trap_manager.c
+++ b/src/libcharon/sa/trap_manager.c
@@ -168,7 +168,7 @@ static bool dynamic_remote_ts(child_cfg_t *child)
traffic_selector_t *ts;
bool found = FALSE;
- other_ts = child->get_traffic_selectors(child, FALSE, NULL, NULL);
+ other_ts = child->get_traffic_selectors(child, FALSE, NULL, NULL, FALSE);
enumerator = other_ts->create_enumerator(other_ts);
while (enumerator->enumerate(enumerator, &ts))
{
@@ -296,11 +296,11 @@ METHOD(trap_manager_t, install, bool,
child_sa = child_sa_create(me, other, child, 0, FALSE, 0, 0);
list = linked_list_create_with_items(me, NULL);
- my_ts = child->get_traffic_selectors(child, TRUE, NULL, list);
+ my_ts = child->get_traffic_selectors(child, TRUE, NULL, list, FALSE);
list->destroy_offset(list, offsetof(host_t, destroy));
list = linked_list_create_with_items(other, NULL);
- other_ts = child->get_traffic_selectors(child, FALSE, NULL, list);
+ other_ts = child->get_traffic_selectors(child, FALSE, NULL, list, FALSE);
list->destroy_offset(list, offsetof(host_t, destroy));
/* We don't know the finally negotiated protocol (ESP|AH), we install