Implemented quick mode protocol handling, no CHILD_SA or HASH payloads yet

This commit is contained in:
Martin Willi
2012-03-20 17:30:47 +01:00
parent cc9629d87c
commit 21b7db99c6
2 changed files with 294 additions and 7 deletions
+2 -1
View File
@@ -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;
+292 -6
View File
@@ -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,
);