ikev2: Destroy IKE_SA when receiving invalid authenticated requests

RFC 7296, section 2.21.3:

   If a peer parsing a request notices that it is badly formatted (after
   it has passed the message authentication code checks and window
   checks) and it returns an INVALID_SYNTAX notification, then this
   error notification is considered fatal in both peers, meaning that
   the IKE SA is deleted without needing an explicit Delete payload.
This commit is contained in:
Tobias Brunner 2019-11-25 14:43:36 +01:00
parent 51ac22579d
commit 10e0faf477
1 changed files with 48 additions and 17 deletions

View File

@ -1324,17 +1324,36 @@ static void send_notify_response(private_task_manager_t *this,
response->destroy(response);
}
/**
* Send an INVALID_SYNTAX notify and destroy the IKE_SA for authenticated
* messages.
*/
static status_t send_invalid_syntax(private_task_manager_t *this,
message_t *msg)
{
send_notify_response(this, msg, INVALID_SYNTAX, chunk_empty);
incr_mid(this, FALSE);
/* IKE_SA_INIT is currently the only type the parser accepts unprotected,
* don't destroy the IKE_SA if such a message is invalid */
if (msg->get_exchange_type(msg) == IKE_SA_INIT)
{
return FAILED;
}
return DESTROY_ME;
}
/**
* Parse the given message and verify that it is valid.
*/
static status_t parse_message(private_task_manager_t *this, message_t *msg)
{
status_t status;
status_t parse_status, status;
uint8_t type = 0;
status = msg->parse_body(msg, this->ike_sa->get_keymat(this->ike_sa));
parse_status = msg->parse_body(msg, this->ike_sa->get_keymat(this->ike_sa));
if (status == SUCCESS)
if (parse_status == SUCCESS)
{ /* check for unsupported critical payloads */
enumerator_t *enumerator;
unknown_payload_t *unknown;
@ -1350,8 +1369,8 @@ static status_t parse_message(private_task_manager_t *this, message_t *msg)
{
type = unknown->get_type(unknown);
DBG1(DBG_ENC, "payload type %N is not supported, "
"but its critical!", payload_type_names, type);
status = NOT_SUPPORTED;
"but payload is critical!", payload_type_names, type);
parse_status = NOT_SUPPORTED;
break;
}
}
@ -1359,11 +1378,13 @@ static status_t parse_message(private_task_manager_t *this, message_t *msg)
enumerator->destroy(enumerator);
}
if (status != SUCCESS)
status = parse_status;
if (parse_status != SUCCESS)
{
bool is_request = msg->get_request(msg);
switch (status)
switch (parse_status)
{
case NOT_SUPPORTED:
DBG1(DBG_IKE, "critical unknown payloads found");
@ -1379,18 +1400,14 @@ static status_t parse_message(private_task_manager_t *this, message_t *msg)
DBG1(DBG_IKE, "message parsing failed");
if (is_request)
{
send_notify_response(this, msg,
INVALID_SYNTAX, chunk_empty);
incr_mid(this, FALSE);
status = send_invalid_syntax(this, msg);
}
break;
case VERIFY_ERROR:
DBG1(DBG_IKE, "message verification failed");
if (is_request)
{
send_notify_response(this, msg,
INVALID_SYNTAX, chunk_empty);
incr_mid(this, FALSE);
status = send_invalid_syntax(this, msg);
}
break;
case FAILED:
@ -1407,11 +1424,25 @@ static status_t parse_message(private_task_manager_t *this, message_t *msg)
is_request ? "request" : "response",
msg->get_message_id(msg));
charon->bus->alert(charon->bus, ALERT_PARSE_ERROR_BODY, msg, status);
charon->bus->alert(charon->bus, ALERT_PARSE_ERROR_BODY, msg,
parse_status);
if (this->ike_sa->get_state(this->ike_sa) == IKE_CREATED)
{ /* invalid initiation attempt, close SA */
return DESTROY_ME;
switch (this->ike_sa->get_state(this->ike_sa))
{
case IKE_CREATED:
/* invalid initiation attempt, close SA */
status = DESTROY_ME;
break;
case IKE_CONNECTING:
case IKE_REKEYED:
/* don't trigger updown event in these states */
break;
default:
if (status == DESTROY_ME)
{
charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
}
break;
}
}
return status;