Merge branch 'init-auth-fail'

Properly notifies the responder if authentication of an IKE_SA or installation
of a CHILD_SA fails as initiator, keeping SA state on peers consistent.
This commit is contained in:
Martin Willi
2013-06-11 15:54:27 +02:00
4 changed files with 79 additions and 2 deletions
+6
View File
@@ -849,6 +849,12 @@ static status_t process_request(private_task_manager_t *this,
task = (task_t*)ike_auth_lifetime_create(
this->ike_sa, FALSE);
break;
case AUTHENTICATION_FAILED:
/* initiator failed to authenticate us.
* We use ike_delete to handle this, which
* invokes all the required hooks. */
task = (task_t*)ike_delete_create(
this->ike_sa, FALSE);
default:
break;
}
+36 -2
View File
@@ -27,6 +27,7 @@
#include <encoding/payloads/ts_payload.h>
#include <encoding/payloads/nonce_payload.h>
#include <encoding/payloads/notify_payload.h>
#include <encoding/payloads/delete_payload.h>
#include <processing/jobs/delete_ike_sa_job.h>
#include <processing/jobs/inactivity_job.h>
@@ -1159,6 +1160,38 @@ static void raise_alerts(private_child_create_t *this, notify_type_t type)
}
}
METHOD(task_t, build_i_delete, status_t,
private_child_create_t *this, message_t *message)
{
message->set_exchange_type(message, INFORMATIONAL);
if (this->child_sa)
{
protocol_id_t proto;
delete_payload_t *del;
u_int32_t spi;
proto = this->child_sa->get_protocol(this->child_sa);
spi = this->child_sa->get_spi(this->child_sa, TRUE);
del = delete_payload_create(DELETE, proto);
del->add_spi(del, spi);
message->add_payload(message, (payload_t*)del);
DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x",
protocol_id_names, proto, ntohl(spi));
}
return NEED_MORE;
}
/**
* Change task to delete the failed CHILD_SA as initiator
*/
static status_t delete_failed_sa(private_child_create_t *this)
{
this->public.task.build = _build_i_delete;
this->public.task.process = (void*)return_success;
return NEED_MORE;
}
METHOD(task_t, process_i, status_t,
private_child_create_t *this, message_t *message)
{
@@ -1260,7 +1293,7 @@ METHOD(task_t, process_i, status_t,
DBG1(DBG_IKE, "received an IPCOMP_SUPPORTED notify without requesting"
" one, no CHILD_SA built");
handle_child_sa_failure(this, message);
return SUCCESS;
return delete_failed_sa(this);
}
else if (this->ipcomp != IPCOMP_NONE && this->ipcomp_received == IPCOMP_NONE)
{
@@ -1273,7 +1306,7 @@ METHOD(task_t, process_i, status_t,
DBG1(DBG_IKE, "received an IPCOMP_SUPPORTED notify we didn't propose, "
"no CHILD_SA built");
handle_child_sa_failure(this, message);
return SUCCESS;
return delete_failed_sa(this);
}
if (select_and_install(this, no_dh, ike_auth) == SUCCESS)
@@ -1295,6 +1328,7 @@ METHOD(task_t, process_i, status_t,
else
{
handle_child_sa_failure(this, message);
return delete_failed_sa(this);
}
return SUCCESS;
}
+29
View File
@@ -852,6 +852,33 @@ local_auth_failed:
return FAILED;
}
/**
* Send an INFORMATIONAL message with an AUTH_FAILED before closing IKE_SA
*/
static void send_auth_failed_informational(private_ike_auth_t *this,
message_t *reply)
{
message_t *message;
packet_t *packet;
host_t *host;
message = message_create(IKEV2_MAJOR_VERSION, IKEV2_MINOR_VERSION);
message->set_message_id(message, reply->get_message_id(reply) + 1);
host = this->ike_sa->get_my_host(this->ike_sa);
message->set_source(message, host->clone(host));
host = this->ike_sa->get_other_host(this->ike_sa);
message->set_destination(message, host->clone(host));
message->set_exchange_type(message, INFORMATIONAL);
message->add_notify(message, FALSE, AUTHENTICATION_FAILED, chunk_empty);
if (this->ike_sa->generate_message(this->ike_sa, message,
&packet) == SUCCESS)
{
charon->sender->send(charon->sender, packet);
}
message->destroy(message);
}
METHOD(task_t, process_i, status_t,
private_ike_auth_t *this, message_t *message)
{
@@ -1005,6 +1032,7 @@ METHOD(task_t, process_i, status_t,
break;
default:
charon->bus->alert(charon->bus, ALERT_LOCAL_AUTH_FAILED);
send_auth_failed_informational(this, message);
return FAILED;
}
}
@@ -1049,6 +1077,7 @@ METHOD(task_t, process_i, status_t,
peer_auth_failed:
charon->bus->alert(charon->bus, ALERT_PEER_AUTH_FAILED);
send_auth_failed_informational(this, message);
return FAILED;
}
@@ -109,6 +109,14 @@ METHOD(task_t, process_r, status_t,
this->ike_sa->get_other_host(this->ike_sa),
this->ike_sa->get_other_id(this->ike_sa));
if (message->get_exchange_type(message) == INFORMATIONAL &&
message->get_notify(message, AUTHENTICATION_FAILED))
{
/* a late AUTHENTICATION_FAILED notify from the initiator after
* we have established the IKE_SA: signal auth failure */
charon->bus->alert(charon->bus, ALERT_LOCAL_AUTH_FAILED);
}
switch (this->ike_sa->get_state(this->ike_sa))
{
case IKE_ESTABLISHED: