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 */
|
||||
this->passive_tasks->remove_at(this->passive_tasks, enumerator);
|
||||
task->destroy(task);
|
||||
break;
|
||||
enumerator->destroy(enumerator);
|
||||
return SUCCESS;
|
||||
case NEED_MORE:
|
||||
/* processed, but task needs at least another call to build() */
|
||||
break;
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
#include <string.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;
|
||||
|
||||
@@ -74,31 +77,316 @@ struct private_quick_mode_t {
|
||||
/** states of quick mode */
|
||||
enum {
|
||||
QM_INIT,
|
||||
QM_NEGOTIATED,
|
||||
} state;
|
||||
};
|
||||
|
||||
METHOD(task_t, build_i, status_t,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
@@ -143,8 +431,6 @@ quick_mode_t *quick_mode_create(ike_sa_t *ike_sa, child_cfg_t *config,
|
||||
},
|
||||
},
|
||||
.ike_sa = ike_sa,
|
||||
.tsi = tsi ? tsi->clone(tsi) : NULL,
|
||||
.tsr = tsr ? tsr->clone(tsr) : NULL,
|
||||
.config = config,
|
||||
.state = QM_INIT,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user