child-create: Initiate and handle childless IKE_SAs according to RFC 6023

This commit is contained in:
Tobias Brunner 2019-03-29 16:46:59 +01:00
parent 93104d0fe9
commit ed521a7470
1 changed files with 87 additions and 0 deletions

View File

@ -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;