Implemented quick mode protocol handling, no CHILD_SA or HASH payloads yet
This commit is contained in:
@@ -454,7 +454,8 @@ static status_t process_request(private_task_manager_t *this,
|
|||||||
/* task completed, remove it */
|
/* task completed, remove it */
|
||||||
this->passive_tasks->remove_at(this->passive_tasks, enumerator);
|
this->passive_tasks->remove_at(this->passive_tasks, enumerator);
|
||||||
task->destroy(task);
|
task->destroy(task);
|
||||||
break;
|
enumerator->destroy(enumerator);
|
||||||
|
return SUCCESS;
|
||||||
case NEED_MORE:
|
case NEED_MORE:
|
||||||
/* processed, but task needs at least another call to build() */
|
/* processed, but task needs at least another call to build() */
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -18,6 +18,9 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <daemon.h>
|
#include <daemon.h>
|
||||||
|
#include <encoding/payloads/sa_payload.h>
|
||||||
|
#include <encoding/payloads/nonce_payload.h>
|
||||||
|
#include <encoding/payloads/id_payload.h>
|
||||||
|
|
||||||
typedef struct private_quick_mode_t private_quick_mode_t;
|
typedef struct private_quick_mode_t private_quick_mode_t;
|
||||||
|
|
||||||
@@ -74,31 +77,316 @@ struct private_quick_mode_t {
|
|||||||
/** states of quick mode */
|
/** states of quick mode */
|
||||||
enum {
|
enum {
|
||||||
QM_INIT,
|
QM_INIT,
|
||||||
|
QM_NEGOTIATED,
|
||||||
} state;
|
} state;
|
||||||
};
|
};
|
||||||
|
|
||||||
METHOD(task_t, build_i, status_t,
|
METHOD(task_t, build_i, status_t,
|
||||||
private_quick_mode_t *this, message_t *message)
|
private_quick_mode_t *this, message_t *message)
|
||||||
{
|
{
|
||||||
return NEED_MORE;
|
switch (this->state)
|
||||||
|
{
|
||||||
|
case QM_INIT:
|
||||||
|
{
|
||||||
|
sa_payload_t *sa_payload;
|
||||||
|
nonce_payload_t *nonce_payload;
|
||||||
|
id_payload_t *id_payload;
|
||||||
|
traffic_selector_t *ts;
|
||||||
|
linked_list_t *list;
|
||||||
|
rng_t *rng;
|
||||||
|
|
||||||
|
list = this->config->get_proposals(this->config, TRUE);
|
||||||
|
sa_payload = sa_payload_create_from_proposal_list(
|
||||||
|
SECURITY_ASSOCIATION_V1, list);
|
||||||
|
list->destroy_offset(list, offsetof(proposal_t, destroy));
|
||||||
|
message->add_payload(message, &sa_payload->payload_interface);
|
||||||
|
|
||||||
|
rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
|
||||||
|
if (!rng)
|
||||||
|
{
|
||||||
|
DBG1(DBG_IKE, "no RNG found to create nonce");
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
rng->allocate_bytes(rng, NONCE_SIZE, &this->nonce_i);
|
||||||
|
rng->destroy(rng);
|
||||||
|
nonce_payload = nonce_payload_create(NONCE_V1);
|
||||||
|
nonce_payload->set_nonce(nonce_payload, this->nonce_i);
|
||||||
|
message->add_payload(message, &nonce_payload->payload_interface);
|
||||||
|
|
||||||
|
list = this->config->get_traffic_selectors(this->config, TRUE, NULL,
|
||||||
|
this->ike_sa->get_my_host(this->ike_sa));
|
||||||
|
if (list->get_first(list, (void**)&ts) != SUCCESS)
|
||||||
|
{
|
||||||
|
list->destroy_offset(list, offsetof(traffic_selector_t, destroy));
|
||||||
|
DBG1(DBG_IKE, "traffic selector missing");
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
id_payload = id_payload_create_from_ts(ts);
|
||||||
|
this->tsi = ts->clone(ts);
|
||||||
|
list->destroy_offset(list, offsetof(traffic_selector_t, destroy));
|
||||||
|
message->add_payload(message, &id_payload->payload_interface);
|
||||||
|
|
||||||
|
list = this->config->get_traffic_selectors(this->config, FALSE, NULL,
|
||||||
|
this->ike_sa->get_other_host(this->ike_sa));
|
||||||
|
if (list->get_first(list, (void**)&ts) != SUCCESS)
|
||||||
|
{
|
||||||
|
list->destroy_offset(list, offsetof(traffic_selector_t, destroy));
|
||||||
|
DBG1(DBG_IKE, "traffic selector missing");
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
id_payload = id_payload_create_from_ts(ts);
|
||||||
|
this->tsr = ts->clone(ts);
|
||||||
|
list->destroy_offset(list, offsetof(traffic_selector_t, destroy));
|
||||||
|
message->add_payload(message, &id_payload->payload_interface);
|
||||||
|
|
||||||
|
/* TODO-IKEv1: Add HASH(1) */
|
||||||
|
|
||||||
|
return NEED_MORE;
|
||||||
|
}
|
||||||
|
case QM_NEGOTIATED:
|
||||||
|
{
|
||||||
|
/* TODO-IKEv1: Send HASH(3) */
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(task_t, process_r, status_t,
|
METHOD(task_t, process_r, status_t,
|
||||||
private_quick_mode_t *this, message_t *message)
|
private_quick_mode_t *this, message_t *message)
|
||||||
{
|
{
|
||||||
return NEED_MORE;
|
switch (this->state)
|
||||||
|
{
|
||||||
|
case QM_INIT:
|
||||||
|
{
|
||||||
|
sa_payload_t *sa_payload;
|
||||||
|
nonce_payload_t *nonce_payload;
|
||||||
|
id_payload_t *id_payload;
|
||||||
|
payload_t *payload;
|
||||||
|
linked_list_t *tsi, *tsr, *list;
|
||||||
|
peer_cfg_t *peer_cfg;
|
||||||
|
host_t *me, *other;
|
||||||
|
enumerator_t *enumerator;
|
||||||
|
bool first = TRUE;
|
||||||
|
|
||||||
|
enumerator = message->create_payload_enumerator(message);
|
||||||
|
while (enumerator->enumerate(enumerator, &payload))
|
||||||
|
{
|
||||||
|
if (payload->get_type(payload) == ID_V1)
|
||||||
|
{
|
||||||
|
id_payload = (id_payload_t*)payload;
|
||||||
|
|
||||||
|
if (first)
|
||||||
|
{
|
||||||
|
this->tsi = id_payload->get_ts(id_payload);
|
||||||
|
first = FALSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->tsr = id_payload->get_ts(id_payload);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
enumerator->destroy(enumerator);
|
||||||
|
|
||||||
|
/* TODO-IKEv1: create host2host TS if ID payloads missing */
|
||||||
|
|
||||||
|
me = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
|
||||||
|
if (!me)
|
||||||
|
{
|
||||||
|
me = this->ike_sa->get_my_host(this->ike_sa);
|
||||||
|
}
|
||||||
|
other = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE);
|
||||||
|
if (!other)
|
||||||
|
{
|
||||||
|
other = this->ike_sa->get_other_host(this->ike_sa);
|
||||||
|
}
|
||||||
|
peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
|
||||||
|
tsi = linked_list_create();
|
||||||
|
tsr = linked_list_create();
|
||||||
|
tsi->insert_last(tsi, this->tsi);
|
||||||
|
tsr->insert_last(tsr, this->tsr);
|
||||||
|
this->config = peer_cfg->select_child_cfg(peer_cfg, tsr, tsi,
|
||||||
|
me, other);
|
||||||
|
tsi->destroy(tsi);
|
||||||
|
tsr->destroy(tsr);
|
||||||
|
if (!this->config)
|
||||||
|
{
|
||||||
|
DBG1(DBG_IKE, "no child config found");
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
sa_payload = (sa_payload_t*)message->get_payload(message,
|
||||||
|
SECURITY_ASSOCIATION_V1);
|
||||||
|
if (!sa_payload)
|
||||||
|
{
|
||||||
|
DBG1(DBG_IKE, "sa payload missing");
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
list = sa_payload->get_proposals(sa_payload);
|
||||||
|
this->proposal = this->config->select_proposal(this->config,
|
||||||
|
list, TRUE, FALSE);
|
||||||
|
list->destroy_offset(list, offsetof(proposal_t, destroy));
|
||||||
|
if (!this->proposal)
|
||||||
|
{
|
||||||
|
DBG1(DBG_IKE, "no matching proposal found");
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
nonce_payload = (nonce_payload_t*)message->get_payload(message,
|
||||||
|
NONCE_V1);
|
||||||
|
if (!nonce_payload)
|
||||||
|
{
|
||||||
|
DBG1(DBG_IKE, "Nonce payload missing");
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
this->nonce_i = nonce_payload->get_nonce(nonce_payload);
|
||||||
|
|
||||||
|
/* TODO-IKEv1: verify HASH(1) */
|
||||||
|
|
||||||
|
return NEED_MORE;
|
||||||
|
}
|
||||||
|
case QM_NEGOTIATED:
|
||||||
|
{
|
||||||
|
/* TODO-IKEv1: verify HASH(3) */
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(task_t, build_r, status_t,
|
METHOD(task_t, build_r, status_t,
|
||||||
private_quick_mode_t *this, message_t *message)
|
private_quick_mode_t *this, message_t *message)
|
||||||
{
|
{
|
||||||
return SUCCESS;
|
switch (this->state)
|
||||||
|
{
|
||||||
|
case QM_INIT:
|
||||||
|
{
|
||||||
|
sa_payload_t *sa_payload;
|
||||||
|
nonce_payload_t *nonce_payload;
|
||||||
|
id_payload_t *id_payload;
|
||||||
|
rng_t *rng;
|
||||||
|
|
||||||
|
sa_payload = sa_payload_create_from_proposal(
|
||||||
|
SECURITY_ASSOCIATION_V1, this->proposal);
|
||||||
|
message->add_payload(message, &sa_payload->payload_interface);
|
||||||
|
|
||||||
|
rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
|
||||||
|
if (!rng)
|
||||||
|
{
|
||||||
|
DBG1(DBG_IKE, "no RNG found to create nonce");
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
rng->allocate_bytes(rng, NONCE_SIZE, &this->nonce_r);
|
||||||
|
rng->destroy(rng);
|
||||||
|
nonce_payload = nonce_payload_create(NONCE_V1);
|
||||||
|
nonce_payload->set_nonce(nonce_payload, this->nonce_r);
|
||||||
|
message->add_payload(message, &nonce_payload->payload_interface);
|
||||||
|
|
||||||
|
id_payload = id_payload_create_from_ts(this->tsi);
|
||||||
|
message->add_payload(message, &id_payload->payload_interface);
|
||||||
|
id_payload = id_payload_create_from_ts(this->tsr);
|
||||||
|
message->add_payload(message, &id_payload->payload_interface);
|
||||||
|
|
||||||
|
/* TODO-IKEv1: add HASH(2) */
|
||||||
|
|
||||||
|
this->state = QM_NEGOTIATED;
|
||||||
|
return NEED_MORE;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(task_t, process_i, status_t,
|
METHOD(task_t, process_i, status_t,
|
||||||
private_quick_mode_t *this, message_t *message)
|
private_quick_mode_t *this, message_t *message)
|
||||||
{
|
{
|
||||||
return SUCCESS;
|
switch (this->state)
|
||||||
|
{
|
||||||
|
case QM_INIT:
|
||||||
|
{
|
||||||
|
sa_payload_t *sa_payload;
|
||||||
|
nonce_payload_t *nonce_payload;
|
||||||
|
id_payload_t *id_payload;
|
||||||
|
payload_t *payload;
|
||||||
|
traffic_selector_t *tsi = NULL, *tsr = NULL;
|
||||||
|
linked_list_t *list;
|
||||||
|
enumerator_t *enumerator;
|
||||||
|
bool first = TRUE;
|
||||||
|
|
||||||
|
enumerator = message->create_payload_enumerator(message);
|
||||||
|
while (enumerator->enumerate(enumerator, &payload))
|
||||||
|
{
|
||||||
|
if (payload->get_type(payload) == ID_V1)
|
||||||
|
{
|
||||||
|
id_payload = (id_payload_t*)payload;
|
||||||
|
|
||||||
|
if (first)
|
||||||
|
{
|
||||||
|
tsi = id_payload->get_ts(id_payload);
|
||||||
|
first = FALSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tsr = id_payload->get_ts(id_payload);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
enumerator->destroy(enumerator);
|
||||||
|
|
||||||
|
/* TODO-IKEv1: create host2host TS if ID payloads missing */
|
||||||
|
|
||||||
|
if (!tsr->is_contained_in(tsr, this->tsr) ||
|
||||||
|
!tsi->is_contained_in(tsi, this->tsi))
|
||||||
|
{
|
||||||
|
tsi->destroy(tsi);
|
||||||
|
tsr->destroy(tsr);
|
||||||
|
DBG1(DBG_IKE, "TS mismatch");
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
this->tsi->destroy(this->tsi);
|
||||||
|
this->tsr->destroy(this->tsr);
|
||||||
|
this->tsi = tsi;
|
||||||
|
this->tsr = tsr;
|
||||||
|
|
||||||
|
sa_payload = (sa_payload_t*)message->get_payload(message,
|
||||||
|
SECURITY_ASSOCIATION_V1);
|
||||||
|
if (!sa_payload)
|
||||||
|
{
|
||||||
|
DBG1(DBG_IKE, "sa payload missing");
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
list = sa_payload->get_proposals(sa_payload);
|
||||||
|
this->proposal = this->config->select_proposal(this->config,
|
||||||
|
list, TRUE, FALSE);
|
||||||
|
list->destroy_offset(list, offsetof(proposal_t, destroy));
|
||||||
|
if (!this->proposal)
|
||||||
|
{
|
||||||
|
DBG1(DBG_IKE, "no matching proposal found");
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
nonce_payload = (nonce_payload_t*)message->get_payload(message,
|
||||||
|
NONCE_V1);
|
||||||
|
if (!nonce_payload)
|
||||||
|
{
|
||||||
|
DBG1(DBG_IKE, "Nonce payload missing");
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
this->nonce_r = nonce_payload->get_nonce(nonce_payload);
|
||||||
|
|
||||||
|
/* TODO-IKEv1: verify HASH(2) */
|
||||||
|
|
||||||
|
this->state = QM_NEGOTIATED;
|
||||||
|
return NEED_MORE;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(task_t, get_type, task_type_t,
|
METHOD(task_t, get_type, task_type_t,
|
||||||
@@ -143,8 +431,6 @@ quick_mode_t *quick_mode_create(ike_sa_t *ike_sa, child_cfg_t *config,
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
.ike_sa = ike_sa,
|
.ike_sa = ike_sa,
|
||||||
.tsi = tsi ? tsi->clone(tsi) : NULL,
|
|
||||||
.tsr = tsr ? tsr->clone(tsr) : NULL,
|
|
||||||
.config = config,
|
.config = config,
|
||||||
.state = QM_INIT,
|
.state = QM_INIT,
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user