From ed521a7470abd841a876716ee21b408670dbb382 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 29 Mar 2019 16:46:59 +0100 Subject: [PATCH] child-create: Initiate and handle childless IKE_SAs according to RFC 6023 --- src/libcharon/sa/ikev2/tasks/child_create.c | 87 +++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/src/libcharon/sa/ikev2/tasks/child_create.c b/src/libcharon/sa/ikev2/tasks/child_create.c index b80e71d54..ac1f9994a 100644 --- a/src/libcharon/sa/ikev2/tasks/child_create.c +++ b/src/libcharon/sa/ikev2/tasks/child_create.c @@ -1037,6 +1037,31 @@ static void process_payloads(private_child_create_t *this, message_t *message) enumerator->destroy(enumerator); } +/** + * Check if we should defer the creation of this CHILD_SA until after the + * IKE_SA has been established childless. + */ +static status_t defer_child_sa(private_child_create_t *this) +{ + ike_cfg_t *ike_cfg; + + ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); + + if (this->ike_sa->supports_extension(this->ike_sa, EXT_IKE_CHILDLESS)) + { + if (ike_cfg->childless(ike_cfg) == CHILDLESS_FORCE) + { + return NEED_MORE; + } + } + else if (ike_cfg->childless(ike_cfg) == CHILDLESS_FORCE) + { + DBG1(DBG_IKE, "peer does not support childless IKE_SA initiation"); + return DESTROY_ME; + } + return NOT_SUPPORTED; +} + METHOD(task_t, build_i, status_t, private_child_create_t *this, message_t *message) { @@ -1067,6 +1092,19 @@ METHOD(task_t, build_i, status_t, /* send only in the first request, not in subsequent rounds */ return NEED_MORE; } + switch (defer_child_sa(this)) + { + case DESTROY_ME: + /* config mismatch */ + return DESTROY_ME; + case NEED_MORE: + /* defer until after IKE_SA has been established */ + chunk_free(&this->my_nonce); + return NEED_MORE; + default: + /* just continue to establish the CHILD_SA */ + break; + } break; default: break; @@ -1312,6 +1350,37 @@ static child_cfg_t* select_child_cfg(private_child_create_t *this) return child_cfg; } +/** + * Check how to handle a possibly childless IKE_SA + */ +static status_t handle_childless(private_child_create_t *this) +{ + ike_cfg_t *ike_cfg; + + ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); + + if (!this->proposals && !this->tsi && !this->tsr) + { + /* looks like a childless IKE_SA, check if we allow it */ + if (ike_cfg->childless(ike_cfg) == CHILDLESS_NEVER) + { + /* we don't allow childless initiation */ + DBG1(DBG_IKE, "peer tried to initiate a childless IKE_SA"); + return INVALID_STATE; + } + return SUCCESS; + } + + /* the peer apparently wants to create a regular IKE_SA */ + if (ike_cfg->childless(ike_cfg) == CHILDLESS_FORCE) + { + /* reject it if we only allow childless initiation */ + DBG1(DBG_IKE, "peer did not initiate a childless IKE_SA"); + return INVALID_STATE; + } + return NOT_SUPPORTED; +} + METHOD(task_t, build_r, status_t, private_child_create_t *this, message_t *message) { @@ -1348,6 +1417,19 @@ METHOD(task_t, build_r, status_t, { /* no CHILD_SA is created for redirected SAs */ return SUCCESS; } + switch (handle_childless(this)) + { + case SUCCESS: + /* no CHILD_SA built */ + return SUCCESS; + case INVALID_STATE: + message->add_notify(message, FALSE, INVALID_SYNTAX, + chunk_empty); + return FAILED; + default: + /* continue with regular initiation */ + break; + } ike_auth = TRUE; default: break; @@ -1533,6 +1615,11 @@ METHOD(task_t, process_i, status_t, { /* wait until all authentication round completed */ return NEED_MORE; } + if (defer_child_sa(this) == NEED_MORE) + { /* defer until after IKE_SA has been established */ + chunk_free(&this->other_nonce); + return NEED_MORE; + } ike_auth = TRUE; default: break;