From eaafcec190ff05fb59ca3e91ed9e4d01aa532b41 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 17 May 2013 10:22:00 +0200 Subject: [PATCH 1/4] ikev2: if responder authentication fails, send AUTHENTICATION_FAILED According to RFC 5996, we MAY send an INFORMATIONAL message having an AUTHENTICATION_FAILED. We don't do any retransmits, though, but just close the IKE_SA after one message has been sent, avoiding the danger that an unauthenticated IKE_SA stays alive. --- src/libcharon/sa/ikev2/tasks/ike_auth.c | 29 +++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/libcharon/sa/ikev2/tasks/ike_auth.c b/src/libcharon/sa/ikev2/tasks/ike_auth.c index e5c3cb849..8f83c4884 100644 --- a/src/libcharon/sa/ikev2/tasks/ike_auth.c +++ b/src/libcharon/sa/ikev2/tasks/ike_auth.c @@ -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; } From ca74bf7a06d0ecc87f7e0d5704714b487fed0abd Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 17 May 2013 10:30:13 +0200 Subject: [PATCH 2/4] ikev2: close an established IKE_SA when receiving AUTHENTICATION_FAILED RFC 5996 compatible implementations MAY send an INFORMATIONAL message with an AUTHENTICATION_FAILED if the initiator failed to authenticate us. Handle such a message like a DELETE for an IKE_SA. --- src/libcharon/sa/ikev2/task_manager_v2.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c index 5298abf79..839bdb990 100644 --- a/src/libcharon/sa/ikev2/task_manager_v2.c +++ b/src/libcharon/sa/ikev2/task_manager_v2.c @@ -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; } From ff3fff4dc9e06009197f657d426752d9893153ea Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 17 May 2013 10:36:40 +0200 Subject: [PATCH 3/4] ikev2: raise LOCAL_AUTH_FAILED when receiving INFORMATIONAL with AUTH_FAILED --- src/libcharon/sa/ikev2/tasks/ike_delete.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/libcharon/sa/ikev2/tasks/ike_delete.c b/src/libcharon/sa/ikev2/tasks/ike_delete.c index f127b0c15..9bc62bf2a 100644 --- a/src/libcharon/sa/ikev2/tasks/ike_delete.c +++ b/src/libcharon/sa/ikev2/tasks/ike_delete.c @@ -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: From e196c41bd223343f8632d1f64afee0d58b5793fe Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 7 Jun 2013 11:35:43 +0200 Subject: [PATCH 4/4] ikev2: if installing a CHILD_SA as initiator fails, notify the responder --- src/libcharon/sa/ikev2/tasks/child_create.c | 38 +++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/src/libcharon/sa/ikev2/tasks/child_create.c b/src/libcharon/sa/ikev2/tasks/child_create.c index 4e66c3f29..d1116d8a1 100644 --- a/src/libcharon/sa/ikev2/tasks/child_create.c +++ b/src/libcharon/sa/ikev2/tasks/child_create.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -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; }