#include <encoding/payloads/sa_payload.h>
#include <encoding/payloads/ke_payload.h>
#include <encoding/payloads/ts_payload.h>
+#include <encoding/payloads/qske_payload.h>
#include <encoding/payloads/nonce_payload.h>
#include <encoding/payloads/notify_payload.h>
#include <encoding/payloads/delete_payload.h>
*/
diffie_hellman_group_t dh_group;
+ /**
+ * QSKE mechanism implementation
+ */
+ qske_t *qske;
+
+ /**
+ * Handling QSKE failed somehow
+ */
+ bool qske_failed;
+
+ /**
+ * QSKE mechanism to use
+ */
+ qske_mechanism_t qske_mechanism;
+
/**
* IKE_SAs keymat
*/
{
enumerator_t *enumerator;
proposal_t *proposal;
- linked_list_t *other_dh_groups;
- bool found = FALSE;
+ linked_list_t *others;
+ bool found_dh = FALSE, found_qske = FALSE, success = TRUE;
- other_dh_groups = linked_list_create();
+ others = linked_list_create();
enumerator = this->proposals->create_enumerator(this->proposals);
while (enumerator->enumerate(enumerator, &proposal))
{
+ bool moved = FALSE;
+
proposal->set_spi(proposal, this->my_spi);
/* move the selected DH group to the front, if any */
this->dh_group))
{
this->proposals->remove_at(this->proposals, enumerator);
- other_dh_groups->insert_last(other_dh_groups, proposal);
+ others->insert_last(others, proposal);
+ moved = TRUE;
}
else
{
- found = TRUE;
+ found_dh = TRUE;
+ }
+ }
+ /* same for QSKE mechanisms */
+ if (this->qske_mechanism != QSKE_NONE)
+ {
+ if (!proposal->promote_transform(proposal, QSKE_MECHANISM,
+ this->qske_mechanism))
+ {
+ if (!moved)
+ {
+ this->proposals->remove_at(this->proposals, enumerator);
+ /* if the proposal contains the proposed DH group, add it
+ * before any that contains neither */
+ others->insert_first(others, proposal);
+ }
+ }
+ else
+ {
+ found_qske = TRUE;
}
}
}
enumerator->destroy(enumerator);
- enumerator = other_dh_groups->create_enumerator(other_dh_groups);
+ enumerator = others->create_enumerator(others);
while (enumerator->enumerate(enumerator, (void**)&proposal))
{ /* no need to remove from the list as we destroy it anyway*/
this->proposals->insert_last(this->proposals, proposal);
}
enumerator->destroy(enumerator);
- other_dh_groups->destroy(other_dh_groups);
+ others->destroy(others);
- return this->dh_group == MODP_NONE || found;
+ if (this->dh_group != MODP_NONE && !found_dh)
+ {
+ DBG1(DBG_IKE, "requested DH group %N not contained in any of our "
+ "proposals", diffie_hellman_group_names, this->dh_group);
+ success = FALSE;
+ }
+ if (this->qske_mechanism != QSKE_NONE && !found_qske)
+ {
+ DBG1(DBG_IKE, "requested QSKE mechanism %N not contained in any of our "
+ "proposals", qske_mechanism_names, this->qske_mechanism);
+ success = FALSE;
+ }
+ return success;
}
/**
/**
* Install a CHILD_SA for usage, return value:
- * - FAILED: no acceptable proposal
- * - INVALID_ARG: diffie hellman group unacceptable
+ * - FAILED: SPI allocation failed
* - NOT_FOUND: TS unacceptable
*/
-static status_t select_and_install(private_child_create_t *this,
- bool no_dh, bool ike_auth)
+static status_t select_and_install(private_child_create_t *this, bool ike_auth)
{
status_t status, status_i, status_o;
child_sa_outbound_state_t out_state;
chunk_t integ_i = chunk_empty, integ_r = chunk_empty;
linked_list_t *my_ts, *other_ts;
host_t *me, *other;
- bool private, prefer_configured;
-
- if (this->proposals == NULL)
- {
- DBG1(DBG_IKE, "SA payload missing in message");
- return FAILED;
- }
- if (this->tsi == NULL || this->tsr == NULL)
- {
- DBG1(DBG_IKE, "TS payloads missing in message");
- return NOT_FOUND;
- }
me = this->ike_sa->get_my_host(this->ike_sa);
other = this->ike_sa->get_other_host(this->ike_sa);
- 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,
- this->proposals, no_dh, private, prefer_configured);
- if (this->proposal == NULL)
- {
- DBG1(DBG_IKE, "no acceptable proposal found");
- charon->bus->alert(charon->bus, ALERT_PROPOSAL_MISMATCH_CHILD,
- this->proposals);
- return FAILED;
- }
this->other_spi = this->proposal->get_spi(this->proposal);
if (!this->initiator)
}
this->child_sa->set_proposal(this->child_sa, this->proposal);
- if (!this->proposal->has_transform(this->proposal, DIFFIE_HELLMAN_GROUP,
- this->dh_group))
- {
- uint16_t group;
-
- if (this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP,
- &group, NULL))
- {
- 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;
- return INVALID_ARG;
- }
- /* the selected proposal does not use a DH group */
- DBG1(DBG_IKE, "ignoring KE exchange, agreed on a non-PFS proposal");
- DESTROY_IF(this->dh);
- this->dh = NULL;
- this->dh_group = MODP_NONE;
- }
-
if (this->initiator)
{
nonce_i = this->my_nonce;
this->child_sa->set_protocol(this->child_sa,
this->proposal->get_protocol(this->proposal));
- if (this->my_cpi == 0 || this->other_cpi == 0 || this->ipcomp == IPCOMP_NONE)
+ if (this->my_cpi == 0 || this->other_cpi == 0 ||
+ this->ipcomp == IPCOMP_NONE)
{
this->my_cpi = this->other_cpi = 0;
this->ipcomp = IPCOMP_NONE;
}
status_i = status_o = FAILED;
if (this->keymat->derive_child_keys(this->keymat, this->proposal, this->dh,
- NULL, nonce_i, nonce_r, &encr_i, &integ_i, &encr_r, &integ_r))
+ this->qske, nonce_i, nonce_r, &encr_i, &integ_i, &encr_r, &integ_r))
{
if (this->initiator)
{
return SUCCESS;
}
+/**
+ * Select a proposal
+ */
+static bool select_proposal(private_child_create_t *this, bool no_dh)
+{
+ bool private, prefer_configured;
+
+ if (!this->proposals)
+ {
+ DBG1(DBG_IKE, "SA payload missing in message");
+ return FALSE;
+ }
+
+ 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,
+ this->proposals, no_dh, private, prefer_configured);
+ if (!this->proposal)
+ {
+ DBG1(DBG_IKE, "no acceptable proposal found");
+ charon->bus->alert(charon->bus, ALERT_PROPOSAL_MISMATCH_CHILD,
+ this->proposals);
+ return FALSE;
+ }
+ return TRUE;
+}
+
/**
* build the payloads for the message
*/
sa_payload_t *sa_payload;
nonce_payload_t *nonce_payload;
ke_payload_t *ke_payload;
+ qske_payload_t *qske_payload;
ts_payload_t *ts_payload;
kernel_feature_t features;
message->add_payload(message, (payload_t*)ke_payload);
}
+ if (this->qske)
+ {
+ qske_payload = qske_payload_create_from_qske(this->qske,
+ this->initiator);
+ if (!qske_payload)
+ {
+ DBG1(DBG_IKE, "failed to create QSKE payload");
+ return FALSE;
+ }
+ message->add_payload(message, (payload_t*)qske_payload);
+ }
+
/* add TSi/TSr payloads */
ts_payload = ts_payload_create_from_traffic_selectors(TRUE, this->tsi);
message->add_payload(message, (payload_t*)ts_payload);
}
}
+/**
+ * Process a KE payload
+ */
+static void process_ke_payload(private_child_create_t *this,
+ ke_payload_t *ke_payload)
+{
+ if (!this->initiator)
+ {
+ this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat,
+ this->dh_group);
+ }
+ else if (this->dh)
+ {
+ if (this->dh->get_dh_group(this->dh) != this->dh_group)
+ {
+ DBG1(DBG_IKE, "DH group in received payload doesn't match");
+ this->dh_failed = TRUE;
+ }
+ }
+ if (this->dh && !this->dh_failed)
+ {
+ if (!this->dh->set_other_public_value(this->dh,
+ ke_payload->get_key_exchange_data(ke_payload)))
+ {
+ DBG1(DBG_IKE, "applying DH public value failed");
+ this->dh_failed = TRUE;
+ }
+ }
+}
+
+/**
+ * Process a QSKE payload
+ */
+static void process_qske_payload(private_child_create_t *this,
+ qske_payload_t *qske)
+{
+ if (!this->initiator)
+ { /* if failing to create this instance is a failure depends on the
+ * selected proposal */
+ this->qske = this->keymat->create_qske(this->keymat,
+ this->qske_mechanism);
+ if (this->qske &&
+ !this->qske->set_public_key(this->qske, qske->get_qske_data(qske)))
+ {
+ DBG1(DBG_IKE, "failed to set QSKE public key");
+ this->qske_failed = TRUE;
+ }
+ }
+ else if (this->qske)
+ { /* ignore the payload if we didn't propose QSKE */
+ if (this->qske->get_qske_mechanism(this->qske) != this->qske_mechanism)
+ {
+ DBG1(DBG_IKE, "QSKE mechanism in received payload doesn't match");
+ this->qske_failed = TRUE;
+ }
+ else if (!this->qske->set_ciphertext(this->qske,
+ qske->get_qske_data(qske)))
+ {
+ DBG1(DBG_IKE, "failed to decrypt QSKE shared secret");
+ this->qske_failed = TRUE;
+ }
+ }
+}
+
/**
* Read payloads from message
*/
payload_t *payload;
sa_payload_t *sa_payload;
ke_payload_t *ke_payload;
+ qske_payload_t *qske;
ts_payload_t *ts_payload;
/* defaults to TUNNEL mode */
break;
case PLV2_KEY_EXCHANGE:
ke_payload = (ke_payload_t*)payload;
- if (!this->initiator)
- {
- this->dh_group = ke_payload->get_dh_group_number(ke_payload);
- this->dh = this->keymat->keymat.create_dh(
- &this->keymat->keymat, this->dh_group);
- }
- else if (this->dh)
- {
- this->dh_failed = this->dh->get_dh_group(this->dh) !=
- ke_payload->get_dh_group_number(ke_payload);
- }
- 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));
- }
+ this->dh_group = ke_payload->get_dh_group_number(ke_payload);
+ process_ke_payload(this, ke_payload);
+ break;
+ case PLV2_QSKE:
+ qske = (qske_payload_t*)payload;
+ this->qske_mechanism = qske->get_qske_mechanism(qske);
+ process_qske_payload(this, qske);
break;
case PLV2_TS_INITIATOR:
ts_payload = (ts_payload_t*)payload;
host_t *vip;
peer_cfg_t *peer_cfg;
linked_list_t *list;
+ bool no_dh = TRUE;
switch (message->get_exchange_type(message))
{
chunk_empty);
return SUCCESS;
}
- if (!this->retry && this->dh_group == MODP_NONE)
- { /* during a rekeying the group might already be set */
- this->dh_group = this->config->get_algorithm(this->config,
- DIFFIE_HELLMAN_GROUP);
- }
+ no_dh = FALSE;
break;
case IKE_AUTH:
switch (defer_child_sa(this))
this->tsr->insert_first(this->tsr,
this->packet_tsr->clone(this->packet_tsr));
}
- this->proposals = this->config->get_proposals(this->config,
- this->dh_group == MODP_NONE);
+ this->proposals = this->config->get_proposals(this->config, no_dh);
this->mode = this->config->get_mode(this->config);
this->child.if_id_in_def = this->ike_sa->get_if_id(this->ike_sa, TRUE);
return FAILED;
}
- if (!update_and_check_proposals(this))
+ /* FIXME: get a group/mechanism from the IKE_SA if we are not rekeying */
+
+ /* during a rekeying the group might already be set */
+ if (!no_dh && !this->retry)
{
- DBG1(DBG_IKE, "requested DH group %N not contained in any of our "
- "proposals",
- diffie_hellman_group_names, this->dh_group);
- return FAILED;
+ if (this->dh_group == MODP_NONE)
+ {
+ this->dh_group = this->config->get_algorithm(this->config,
+ DIFFIE_HELLMAN_GROUP);
+ }
+ if (this->qske_mechanism == QSKE_NONE)
+ {
+ this->qske_mechanism = this->config->get_algorithm(this->config,
+ QSKE_MECHANISM);
+ }
}
if (this->dh_group != MODP_NONE)
{
this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat,
this->dh_group);
+ if (!this->dh)
+ {
+ DBG1(DBG_IKE, "DH group %N not supported, disabling DH",
+ diffie_hellman_group_names, this->dh_group);
+ this->dh_group = MODP_NONE;
+ }
+ }
+
+ if (this->qske_mechanism != QSKE_NONE)
+ {
+ this->qske = this->keymat->create_qske(this->keymat,
+ this->qske_mechanism);
+ if (!this->qske)
+ {
+ DBG1(DBG_IKE, "QSKE mechanism %N not supported, disabling QSKE",
+ qske_mechanism_names, this->qske_mechanism);
+ this->qske_mechanism = QSKE_NONE;
+ }
+ }
+
+ if (!update_and_check_proposals(this))
+ {
+ return FAILED;
}
if (this->config->has_option(this->config, OPT_IPCOMP))
return NOT_SUPPORTED;
}
+/**
+ * Check if the proposed DH group is valid
+ */
+static bool check_dh_group(private_child_create_t *this, uint16_t *req)
+{
+ uint16_t alg;
+
+ if (!this->proposal->has_transform(this->proposal, DIFFIE_HELLMAN_GROUP,
+ this->dh_group))
+ {
+ if (this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP,
+ &alg, NULL))
+ {
+ if (req)
+ {
+ *req = alg;
+ }
+ return FALSE;
+ }
+ /* the selected proposal does not use a DH group */
+ DBG1(DBG_IKE, "ignoring KE exchange, agreed on a non-PFS proposal");
+ DESTROY_IF(this->dh);
+ this->dh = NULL;
+ this->dh_group = MODP_NONE;
+ /* ignore errors that occurred while handling the KE payload */
+ this->dh_failed = FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * Check if the proposed DH group is valid as responder
+ */
+static bool check_dh_group_r(private_child_create_t *this, message_t *message)
+{
+ uint16_t alg;
+
+ if (!check_dh_group(this, &alg))
+ {
+ DBG1(DBG_IKE, "DH group %N unacceptable, requesting %N",
+ diffie_hellman_group_names, this->dh_group,
+ diffie_hellman_group_names, alg);
+ alg = htons(alg);
+ message->add_notify(message, FALSE, INVALID_KE_PAYLOAD,
+ chunk_from_thing(alg));
+ return FALSE;
+ }
+ else if (this->dh_group != MODP_NONE && !this->dh)
+ {
+ DBG1(DBG_IKE, "negotiated DH group %N not supported",
+ diffie_hellman_group_names, this->dh_group);
+ message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * Check if the proposed QSKE mechanism is valid
+ */
+static bool check_qske_mechanism(private_child_create_t *this, uint16_t *req)
+{
+ uint16_t alg;
+
+ if (!this->proposal->has_transform(this->proposal, QSKE_MECHANISM,
+ this->qske_mechanism))
+ {
+ if (this->proposal->get_algorithm(this->proposal, QSKE_MECHANISM,
+ &alg, NULL))
+ {
+ if (req)
+ {
+ *req = alg;
+ }
+ return FALSE;
+ }
+ /* the selected proposal does not use a QSKE mechanism */
+ DBG1(DBG_IKE, "ignoring QSKE exchange, agreed on a non-QSKE proposal");
+ DESTROY_IF(this->qske);
+ this->qske = NULL;
+ this->qske_mechanism = QSKE_NONE;
+ /* ignore errors that occurred while handling the QSKE payload */
+ this->qske_failed = FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * Check if the proposed QSKE mechanism is usable as responder
+ */
+static bool check_qske_mechanism_r(private_child_create_t *this,
+ message_t *message)
+{
+ uint16_t alg;
+
+ if (!check_qske_mechanism(this, &alg))
+ {
+
+ DBG1(DBG_IKE, "QSKE mechanism %N unacceptable, requesting %N",
+ qske_mechanism_names, this->qske_mechanism,
+ qske_mechanism_names, alg);
+ alg = htons(alg);
+ message->add_notify(message, FALSE, INVALID_QSKE_PAYLOAD,
+ chunk_from_thing(alg));
+ return FALSE;
+ }
+ else if (this->qske_mechanism != QSKE_NONE && !this->qske)
+ {
+ DBG1(DBG_IKE, "negotiated QSKE mechanism %N not supported",
+ qske_mechanism_names, this->qske_mechanism);
+ message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty);
+ return FALSE;
+ }
+ return TRUE;
+}
+
METHOD(task_t, build_r, status_t,
private_child_create_t *this, message_t *message)
{
chunk_empty);
return SUCCESS;
}
- if (this->dh_failed)
- {
- DBG1(DBG_IKE, "applying DH public value failed");
- message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN,
- chunk_empty);
- return SUCCESS;
- }
no_dh = FALSE;
break;
case IKE_AUTH:
return SUCCESS;
}
- if (this->config == NULL)
+ if (!this->config)
{
this->config = select_child_cfg(this);
}
- if (this->config == NULL)
+ if (!this->config || !this->tsi || !this->tsr)
{
- DBG1(DBG_IKE, "traffic selectors %#R === %#R unacceptable",
- this->tsr, this->tsi);
- charon->bus->alert(charon->bus, ALERT_TS_MISMATCH, this->tsi, this->tsr);
+ if (!this->tsi || !this->tsr)
+ {
+ DBG1(DBG_IKE, "TS payloads missing in message");
+ }
+ else
+ {
+ 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);
handle_child_sa_failure(this, message);
return SUCCESS;
}
enumerator->destroy(enumerator);
+ if (!select_proposal(this, no_dh))
+ {
+ message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty);
+ handle_child_sa_failure(this, message);
+ return SUCCESS;
+ }
+
+ if (!check_dh_group_r(this, message))
+ {
+ /* also add an INVALID_QSKE_PAYLOAD notify if necessary */
+ check_qske_mechanism_r(this, message);
+ return SUCCESS;
+ }
+
+ if (!check_qske_mechanism_r(this, message))
+ {
+ return SUCCESS;
+ }
+
+ if (this->dh_failed || this->qske_failed)
+ {
+ message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty);
+ return SUCCESS;
+ }
+
this->child.if_id_in_def = this->ike_sa->get_if_id(this->ike_sa, TRUE);
this->child.if_id_out_def = this->ike_sa->get_if_id(this->ike_sa, FALSE);
this->child.encap = this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY);
}
}
- switch (select_and_install(this, no_dh, ike_auth))
+ switch (select_and_install(this, ike_auth))
{
case SUCCESS:
break;
message->add_notify(message, FALSE, TS_UNACCEPTABLE, chunk_empty);
handle_child_sa_failure(this, message);
return SUCCESS;
- case INVALID_ARG:
- {
- uint16_t group = htons(this->dh_group);
- message->add_notify(message, FALSE, INVALID_KE_PAYLOAD,
- chunk_from_thing(group));
- return SUCCESS;
- }
case FAILED:
default:
message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty);
return SUCCESS;
}
+/**
+ * Handle an INVALID_KE_PAYLOAD notify, look for one if none given
+ */
+static void handle_invalid_ke(private_child_create_t *this, message_t *message,
+ notify_payload_t *notify)
+{
+ chunk_t data;
+ uint16_t alg = this->dh_group;
+
+ if (!notify || notify->get_notify_type(notify) != INVALID_KE_PAYLOAD)
+ {
+ notify = message->get_notify(message, INVALID_KE_PAYLOAD);
+ if (!notify)
+ {
+ return;
+ }
+ }
+ data = notify->get_notification_data(notify);
+ if (data.len == sizeof(alg))
+ {
+ alg = untoh16(data.ptr);
+ }
+ if (this->retry)
+ {
+ DBG1(DBG_IKE, "already retried with DH group %N, ignore"
+ "requested %N", diffie_hellman_group_names, this->dh_group,
+ diffie_hellman_group_names, alg);
+ return;
+ }
+ DBG1(DBG_IKE, "peer didn't accept DH group %N, "
+ "it requested %N", diffie_hellman_group_names, this->dh_group,
+ diffie_hellman_group_names, alg);
+ this->dh_group = alg;
+}
+
+/**
+ * Handle an INVALID_QSKE_PAYLOAD notify, look for one if none given
+ */
+static void handle_invalid_qske(private_child_create_t *this, message_t *message,
+ notify_payload_t *notify)
+{
+ chunk_t data;
+ uint16_t alg = this->qske_mechanism;
+
+ if (!notify || notify->get_notify_type(notify) != INVALID_QSKE_PAYLOAD)
+ {
+ notify = message->get_notify(message, INVALID_QSKE_PAYLOAD);
+ if (!notify)
+ {
+ return;
+ }
+ }
+
+ data = notify->get_notification_data(notify);
+ if (data.len == sizeof(alg))
+ {
+ alg = untoh16(data.ptr);
+ }
+ if (this->retry)
+ {
+ DBG1(DBG_IKE, "already retried with QSKE mechanism %N, ignore"
+ "requested %N", qske_mechanism_names, this->qske_mechanism,
+ qske_mechanism_names, alg);
+ return;
+ }
+ DBG1(DBG_IKE, "peer didn't accept QSKE mechanism %N, "
+ "it requested %N", qske_mechanism_names, this->qske_mechanism,
+ qske_mechanism_names, alg);
+ this->qske_mechanism = alg;
+}
+
METHOD(task_t, process_i, status_t,
private_child_create_t *this, message_t *message)
{
break;
case IKE_AUTH:
if (this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED)
- { /* wait until all authentication round completed */
+ { /* wait until all authentication rounds completed */
return NEED_MORE;
}
if (defer_child_sa(this) == NEED_MORE)
return SUCCESS;
}
case INVALID_KE_PAYLOAD:
+ case INVALID_QSKE_PAYLOAD:
{
- chunk_t data;
- uint16_t group = MODP_NONE;
+ handle_invalid_ke(this, message, notify);
+ handle_invalid_qske(this, message, notify);
- data = notify->get_notification_data(notify);
- if (data.len == sizeof(group))
- {
- memcpy(&group, data.ptr, data.len);
- group = ntohs(group);
- }
+ enumerator->destroy(enumerator);
if (this->retry)
{
- DBG1(DBG_IKE, "already retried with DH group %N, "
- "ignore requested %N", diffie_hellman_group_names,
- this->dh_group, diffie_hellman_group_names, group);
handle_child_sa_failure(this, message);
/* an error in CHILD_SA creation is not critical */
return SUCCESS;
}
- DBG1(DBG_IKE, "peer didn't accept DH group %N, "
- "it requested %N", diffie_hellman_group_names,
- this->dh_group, diffie_hellman_group_names, group);
this->retry = TRUE;
- this->dh_group = group;
this->child_sa->set_state(this->child_sa, CHILD_RETRYING);
this->public.task.migrate(&this->public.task, this->ike_sa);
- enumerator->destroy(enumerator);
return NEED_MORE;
}
default:
return delete_failed_sa(this);
}
- if (this->dh_failed)
+ if (!select_proposal(this, no_dh))
+ {
+ handle_child_sa_failure(this, message);
+ return delete_failed_sa(this);
+ }
+
+ if (!check_dh_group(this, NULL) || !check_qske_mechanism(this, NULL))
+ {
+ DBG1(DBG_IKE, "peer selected a proposal with different DH/QSKE but "
+ "didn't send back a notify");
+ handle_child_sa_failure(this, message);
+ return delete_failed_sa(this);
+ }
+
+ if (this->dh_failed || this->qske_failed)
{
- DBG1(DBG_IKE, "applying DH public value failed");
handle_child_sa_failure(this, message);
return delete_failed_sa(this);
}
- if (select_and_install(this, no_dh, ike_auth) == SUCCESS)
+ if (select_and_install(this, ike_auth) == SUCCESS)
{
if (!this->rekey)
{ /* invoke the child_up() hook if we are not rekeying */
DESTROY_IF(this->child_sa);
DESTROY_IF(this->proposal);
DESTROY_IF(this->nonceg);
+ DESTROY_IF(this->qske);
DESTROY_IF(this->dh);
this->dh_failed = FALSE;
+ this->qske_failed = FALSE;
if (this->proposals)
{
this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
this->tsi = NULL;
this->tsr = NULL;
this->dh = NULL;
+ this->qske = NULL;
this->nonceg = NULL;
this->child_sa = NULL;
this->mode = MODE_TUNNEL;
DESTROY_IF(this->packet_tsi);
DESTROY_IF(this->packet_tsr);
DESTROY_IF(this->proposal);
+ DESTROY_IF(this->qske);
DESTROY_IF(this->dh);
if (this->proposals)
{