merged tasking branch into trunk

This commit is contained in:
Martin Willi
2007-02-28 14:04:36 +00:00
parent a7a5e834e3
commit c60c7694d2
96 changed files with 8409 additions and 8332 deletions
+718
View File
@@ -0,0 +1,718 @@
/**
* @file child_create.c
*
* @brief Implementation of the child_create task.
*
*/
/*
* Copyright (C) 2005-2007 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "child_create.h"
#include <daemon.h>
#include <crypto/diffie_hellman.h>
#include <encoding/payloads/sa_payload.h>
#include <encoding/payloads/ts_payload.h>
#include <encoding/payloads/nonce_payload.h>
#include <encoding/payloads/notify_payload.h>
typedef struct private_child_create_t private_child_create_t;
/**
* Private members of a child_create_t task.
*/
struct private_child_create_t {
/**
* Public methods and task_t interface.
*/
child_create_t public;
/**
* Assigned IKE_SA.
*/
ike_sa_t *ike_sa;
/**
* Are we the initiator?
*/
bool initiator;
/**
* nonce chosen by us
*/
chunk_t my_nonce;
/**
* nonce chosen by peer
*/
chunk_t other_nonce;
/**
* policy to create the CHILD_SA from
*/
policy_t *policy;
/**
* list of proposal candidates
*/
linked_list_t *proposals;
/**
* selected proposal to use for CHILD_SA
*/
proposal_t *proposal;
/**
* traffic selectors for initiators side
*/
linked_list_t *tsi;
/**
* traffic selectors for responders side
*/
linked_list_t *tsr;
/**
* mode the new CHILD_SA uses (transport/tunnel/beet)
*/
mode_t mode;
/**
* reqid to use if we are rekeying
*/
u_int32_t reqid;
/**
* CHILD_SA which gets established
*/
child_sa_t *child_sa;
};
/**
* get the nonce from a message
*/
static status_t get_nonce(message_t *message, chunk_t *nonce)
{
nonce_payload_t *payload;
payload = (nonce_payload_t*)message->get_payload(message, NONCE);
if (payload == NULL)
{
return FAILED;
}
*nonce = payload->get_nonce(payload);
return NEED_MORE;
}
/**
* generate a new nonce to include in a CREATE_CHILD_SA message
*/
static status_t generate_nonce(chunk_t *nonce)
{
status_t status;
randomizer_t *randomizer = randomizer_create();
status = randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE,
nonce);
randomizer->destroy(randomizer);
if (status != SUCCESS)
{
DBG1(DBG_IKE, "error generating random nonce value");
return FAILED;
}
return SUCCESS;
}
/**
* Check a list of traffic selectors if any selector belongs to host
*/
static bool ts_list_is_host(linked_list_t *list, host_t *host)
{
traffic_selector_t *ts;
bool is_host = TRUE;
iterator_t *iterator = list->create_iterator(list, TRUE);
while (is_host && iterator->iterate(iterator, (void**)&ts))
{
is_host = is_host && ts->is_host(ts, host);
}
iterator->destroy(iterator);
return is_host;
}
/**
* Install a CHILD_SA for usage
*/
static status_t select_and_install(private_child_create_t *this)
{
prf_plus_t *prf_plus;
status_t status;
chunk_t nonce_i, nonce_r, seed;
linked_list_t *my_ts, *other_ts;
host_t *me, *other, *other_vip, *my_vip;
if (this->proposals == NULL || this->tsi == NULL || this->tsr == NULL)
{
SIG(CHILD_UP_FAILED, "SA/TS payloads missing in message");
return FAILED;
}
if (this->initiator)
{
nonce_i = this->my_nonce;
nonce_r = this->other_nonce;
my_ts = this->tsi;
other_ts = this->tsr;
}
else
{
nonce_r = this->my_nonce;
nonce_i = this->other_nonce;
my_ts = this->tsr;
other_ts = this->tsi;
}
me = this->ike_sa->get_my_host(this->ike_sa);
other = this->ike_sa->get_other_host(this->ike_sa);
my_vip = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
other_vip = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE);
this->proposal = this->policy->select_proposal(this->policy, this->proposals);
if (this->initiator && my_vip)
{ /* if we have a virtual IP, shorten our TS to the minimum */
my_ts = this->policy->select_my_traffic_selectors(this->policy, my_ts,
my_vip);
}
else
{ /* shorten in the host2host case only */
my_ts = this->policy->select_my_traffic_selectors(this->policy,
my_ts, me);
}
if (other_vip)
{ /* if other has a virtual IP, shorten it's traffic selectors to it */
other_ts = this->policy->select_other_traffic_selectors(this->policy,
other_ts, other_vip);
}
else
{ /* use his host for the host2host case */
other_ts = this->policy->select_other_traffic_selectors(this->policy,
other_ts, other);
}
this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy));
this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
if (this->initiator)
{
this->tsi = my_ts;
this->tsr = other_ts;
}
else
{
this->tsr = my_ts;
this->tsi = other_ts;
}
if (this->proposal == NULL ||
this->tsi->get_count(this->tsi) == 0 ||
this->tsr->get_count(this->tsr) == 0)
{
SIG(CHILD_UP_FAILED, "no acceptable proposal found");
return FAILED;
}
if (!this->initiator)
{
/* check if requested mode is acceptable, downgrade if required */
switch (this->mode)
{
case MODE_TRANSPORT:
if (!ts_list_is_host(this->tsi, other) ||
!ts_list_is_host(this->tsr, me))
{
this->mode = MODE_TUNNEL;
DBG1(DBG_IKE, "not using tranport mode, not host-to-host");
}
else if (this->ike_sa->is_natt_enabled(this->ike_sa))
{
this->mode = MODE_TUNNEL;
DBG1(DBG_IKE, "not using tranport mode, connection NATed");
}
break;
case MODE_BEET:
if (!ts_list_is_host(this->tsi, NULL) ||
!ts_list_is_host(this->tsr, NULL))
{
this->mode = MODE_TUNNEL;
DBG1(DBG_IKE, "not using BEET mode, not host-to-host");
}
break;
default:
break;
}
}
seed = chunk_cata("cc", nonce_i, nonce_r);
prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed);
if (this->initiator)
{
status = this->child_sa->update(this->child_sa, this->proposal,
this->mode, prf_plus);
}
else
{
status = this->child_sa->add(this->child_sa, this->proposal,
this->mode, prf_plus);
}
prf_plus->destroy(prf_plus);
if (status != SUCCESS)
{
SIG(CHILD_UP_FAILED, "unable to install IPsec SA (SAD) in kernel");
return status;
}
status = this->child_sa->add_policies(this->child_sa, my_ts, other_ts,
this->mode);
if (status != SUCCESS)
{
SIG(CHILD_UP_FAILED, "unable to install IPsec policies (SPD) in kernel");
return status;
}
/* add to IKE_SA, and remove from task */
this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
this->child_sa = NULL;
return SUCCESS;
}
/**
* build the payloads for the message
*/
static void build_payloads(private_child_create_t *this, message_t *message)
{
sa_payload_t *sa_payload;
ts_payload_t *ts_payload;
nonce_payload_t *nonce_payload;
/* add SA payload */
if (this->initiator)
{
sa_payload = sa_payload_create_from_proposal_list(this->proposals);
}
else
{
sa_payload = sa_payload_create_from_proposal(this->proposal);
}
message->add_payload(message, (payload_t*)sa_payload);
/* add TSi/TSr payloads */
ts_payload = ts_payload_create_from_traffic_selectors(TRUE, this->tsi);
message->add_payload(message, (payload_t*)ts_payload);
ts_payload = ts_payload_create_from_traffic_selectors(FALSE, this->tsr);
message->add_payload(message, (payload_t*)ts_payload);
/* add nonce payload if not in IKE_AUTH */
if (message->get_exchange_type(message) == CREATE_CHILD_SA)
{
nonce_payload = nonce_payload_create();
nonce_payload->set_nonce(nonce_payload, this->my_nonce);
message->add_payload(message, (payload_t*)nonce_payload);
}
/* add a notify if we are not in tunnel mode */
switch (this->mode)
{
case MODE_TRANSPORT:
message->add_notify(message, FALSE, USE_TRANSPORT_MODE, chunk_empty);
break;
case MODE_BEET:
message->add_notify(message, FALSE, USE_BEET_MODE, chunk_empty);
break;
default:
break;
}
}
/**
* Read payloads from message
*/
static void process_payloads(private_child_create_t *this, message_t *message)
{
iterator_t *iterator;
payload_t *payload;
sa_payload_t *sa_payload;
ts_payload_t *ts_payload;
notify_payload_t *notify_payload;
/* defaults to TUNNEL mode */
this->mode = MODE_TUNNEL;
iterator = message->get_payload_iterator(message);
while (iterator->iterate(iterator, (void**)&payload))
{
switch (payload->get_type(payload))
{
case SECURITY_ASSOCIATION:
sa_payload = (sa_payload_t*)payload;
this->proposals = sa_payload->get_proposals(sa_payload);
break;
case TRAFFIC_SELECTOR_INITIATOR:
ts_payload = (ts_payload_t*)payload;
this->tsi = ts_payload->get_traffic_selectors(ts_payload);
break;
case TRAFFIC_SELECTOR_RESPONDER:
ts_payload = (ts_payload_t*)payload;
this->tsr = ts_payload->get_traffic_selectors(ts_payload);
break;
case NOTIFY:
notify_payload = (notify_payload_t*)payload;
switch (notify_payload ->get_notify_type(notify_payload ))
{
case USE_TRANSPORT_MODE:
this->mode = MODE_TRANSPORT;
break;
case USE_BEET_MODE:
this->mode = MODE_BEET;
break;
default:
break;
}
break;
default:
break;
}
}
iterator->destroy(iterator);
}
/**
* Implementation of task_t.build for initiator
*/
static status_t build_i(private_child_create_t *this, message_t *message)
{
host_t *me, *other, *vip;
switch (message->get_exchange_type(message))
{
case IKE_SA_INIT:
return get_nonce(message, &this->my_nonce);
case CREATE_CHILD_SA:
if (generate_nonce(&this->my_nonce) != SUCCESS)
{
message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty);
return SUCCESS;
}
break;
default:
break;
}
SIG(CHILD_UP_START, "establishing CHILD_SA");
me = this->ike_sa->get_my_host(this->ike_sa);
other = this->ike_sa->get_other_host(this->ike_sa);
vip = this->policy->get_virtual_ip(this->policy, NULL);
if (vip)
{ /* propose a 0.0.0.0/0 subnet when we use virtual ip */
this->tsi = this->policy->get_my_traffic_selectors(this->policy, NULL);
vip->destroy(vip);
}
else
{ /* but shorten a 0.0.0.0/0 subnet to the actual address if host2host */
this->tsi = this->policy->get_my_traffic_selectors(this->policy, me);
}
this->tsr = this->policy->get_other_traffic_selectors(this->policy, other);
this->proposals = this->policy->get_proposals(this->policy);
this->mode = this->policy->get_mode(this->policy);
this->child_sa = child_sa_create(me, other,
this->ike_sa->get_my_id(this->ike_sa),
this->ike_sa->get_other_id(this->ike_sa),
this->policy, this->reqid,
this->ike_sa->is_natt_enabled(this->ike_sa));
if (this->child_sa->alloc(this->child_sa, this->proposals) != SUCCESS)
{
SIG(CHILD_UP_FAILED, "unable to allocate SPIs from kernel");
return FAILED;
}
build_payloads(this, message);
this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy));
this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
this->tsi = NULL;
this->tsr = NULL;
this->proposals = NULL;
return NEED_MORE;
}
/**
* Implementation of task_t.process for initiator
*/
static status_t process_r(private_child_create_t *this, message_t *message)
{
switch (message->get_exchange_type(message))
{
case IKE_SA_INIT:
return get_nonce(message, &this->other_nonce);
case CREATE_CHILD_SA:
get_nonce(message, &this->other_nonce);
break;
default:
break;
}
process_payloads(this, message);
if (this->tsi == NULL || this->tsr == NULL)
{
DBG1(DBG_IKE, "TS payload missing in message");
return NEED_MORE;
}
this->policy = charon->policies->get_policy(charon->policies,
this->ike_sa->get_my_id(this->ike_sa),
this->ike_sa->get_other_id(this->ike_sa),
this->tsr, this->tsi,
this->ike_sa->get_my_host(this->ike_sa),
this->ike_sa->get_other_host(this->ike_sa));
if (this->policy && this->ike_sa->get_policy(this->ike_sa) == NULL)
{
this->ike_sa->set_policy(this->ike_sa, this->policy);
}
return NEED_MORE;
}
/**
* Implementation of task_t.build for responder
*/
static status_t build_r(private_child_create_t *this, message_t *message)
{
switch (message->get_exchange_type(message))
{
case IKE_SA_INIT:
return get_nonce(message, &this->my_nonce);
case CREATE_CHILD_SA:
if (generate_nonce(&this->my_nonce) != SUCCESS)
{
message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty);
return SUCCESS;
}
break;
default:
break;
}
if (this->policy == NULL)
{
SIG(CHILD_UP_FAILED, "received traffic selectors inacceptable");
message->add_notify(message, FALSE, TS_UNACCEPTABLE, chunk_empty);
return SUCCESS;
}
this->child_sa = child_sa_create(this->ike_sa->get_my_host(this->ike_sa),
this->ike_sa->get_other_host(this->ike_sa),
this->ike_sa->get_my_id(this->ike_sa),
this->ike_sa->get_other_id(this->ike_sa),
this->policy, this->reqid,
this->ike_sa->is_natt_enabled(this->ike_sa));
if (select_and_install(this) != SUCCESS)
{
message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty);
return SUCCESS;
}
build_payloads(this, message);
SIG(CHILD_UP_SUCCESS, "established CHILD_SA successfully");
return SUCCESS;
}
/**
* Implementation of task_t.process for initiator
*/
static status_t process_i(private_child_create_t *this, message_t *message)
{
iterator_t *iterator;
payload_t *payload;
status_t status;
switch (message->get_exchange_type(message))
{
case IKE_SA_INIT:
return get_nonce(message, &this->other_nonce);
case CREATE_CHILD_SA:
get_nonce(message, &this->other_nonce);
break;
default:
break;
}
/* check for erronous notifies */
iterator = message->get_payload_iterator(message);
while (iterator->iterate(iterator, (void**)&payload))
{
if (payload->get_type(payload) == NOTIFY)
{
notify_payload_t *notify = (notify_payload_t*)payload;
notify_type_t type = notify->get_notify_type(notify);
if (type < 16383)
{
SIG(CHILD_UP_FAILED, "received %N notify error",
notify_type_names, type);
iterator->destroy(iterator);
/* an error in CHILD_SA creation is not critical */
return SUCCESS;
}
}
}
iterator->destroy(iterator);
process_payloads(this, message);
status = select_and_install(this);
SIG(CHILD_UP_SUCCESS, "established CHILD_SA successfully");
return SUCCESS;
}
/**
* Implementation of task_t.get_type
*/
static task_type_t get_type(private_child_create_t *this)
{
return CHILD_CREATE;
}
/**
* Implementation of child_create_t.use_reqid
*/
static void use_reqid(private_child_create_t *this, u_int32_t reqid)
{
this->reqid = reqid;
}
/**
* Implementation of task_t.migrate
*/
static void migrate(private_child_create_t *this, ike_sa_t *ike_sa)
{
chunk_free(&this->my_nonce);
chunk_free(&this->other_nonce);
if (this->tsi)
{
this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy));
}
if (this->tsr)
{
this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
}
DESTROY_IF(this->child_sa);
DESTROY_IF(this->proposal);
if (this->proposals)
{
this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
}
this->ike_sa = ike_sa;
this->proposals = NULL;
this->tsi = NULL;
this->tsr = NULL;
this->child_sa = NULL;
this->mode = MODE_TUNNEL;
this->reqid = 0;
}
/**
* Implementation of task_t.destroy
*/
static void destroy(private_child_create_t *this)
{
chunk_free(&this->my_nonce);
chunk_free(&this->other_nonce);
if (this->tsi)
{
this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy));
}
if (this->tsr)
{
this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
}
DESTROY_IF(this->child_sa);
DESTROY_IF(this->proposal);
if (this->proposals)
{
this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
}
DESTROY_IF(this->policy);
free(this);
}
/*
* Described in header.
*/
child_create_t *child_create_create(ike_sa_t *ike_sa, policy_t *policy)
{
private_child_create_t *this = malloc_thing(private_child_create_t);
this->public.use_reqid = (void(*)(child_create_t*,u_int32_t))use_reqid;
this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
this->public.task.destroy = (void(*)(task_t*))destroy;
if (policy)
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
this->initiator = TRUE;
policy->get_ref(policy);
}
else
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
this->initiator = FALSE;
}
this->ike_sa = ike_sa;
this->policy = policy;
this->my_nonce = chunk_empty;
this->other_nonce = chunk_empty;
this->proposals = NULL;
this->proposal = NULL;
this->tsi = NULL;
this->tsr = NULL;
this->child_sa = NULL;
this->mode = MODE_TUNNEL;
this->reqid = 0;
return &this->public;
}
+72
View File
@@ -0,0 +1,72 @@
/**
* @file child_create.h
*
* @brief Interface child_create_t.
*
*/
/*
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef CHILD_CREATE_H_
#define CHILD_CREATE_H_
typedef struct child_create_t child_create_t;
#include <library.h>
#include <sa/ike_sa.h>
#include <sa/tasks/task.h>
#include <config/policies/policy.h>
/**
* @brief Task of type CHILD_CREATE, established a new CHILD_SA.
*
* This task may be included in the IKE_AUTH message or in a separate
* CREATE_CHILD_SA exchange.
*
* @b Constructors:
* - child_create_create()
*
* @ingroup tasks
*/
struct child_create_t {
/**
* Implements the task_t interface
*/
task_t task;
/**
* @brief Use a specific reqid for the CHILD_SA.
*
* When this task is used for rekeying, the same reqid is used
* for the new CHILD_SA.
*
* @param this calling object
* @param reqid reqid to use
*/
void (*use_reqid) (child_create_t *this, u_int32_t reqid);
};
/**
* @brief Create a new child_create task.
*
* @param ike_sa IKE_SA this task works for
* @param policy policy if task initiator, NULL if responder
* @return child_create task to handle by the task_manager
*/
child_create_t *child_create_create(ike_sa_t *ike_sa, policy_t *policy);
#endif /* CHILD_CREATE_H_ */
+264
View File
@@ -0,0 +1,264 @@
/**
* @file child_delete.c
*
* @brief Implementation of the child_delete task.
*
*/
/*
* Copyright (C) 2006-2007 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "child_delete.h"
#include <daemon.h>
#include <encoding/payloads/delete_payload.h>
typedef struct private_child_delete_t private_child_delete_t;
/**
* Private members of a child_delete_t task.
*/
struct private_child_delete_t {
/**
* Public methods and task_t interface.
*/
child_delete_t public;
/**
* Assigned IKE_SA.
*/
ike_sa_t *ike_sa;
/**
* Are we the initiator?
*/
bool initiator;
/**
* CHILD_SAs which get deleted
*/
linked_list_t *child_sas;
};
/**
* build the delete payloads from the listed child_sas
*/
static void build_payloads(private_child_delete_t *this, message_t *message)
{
iterator_t *iterator;
delete_payload_t *ah = NULL, *esp = NULL;
u_int32_t spi;
child_sa_t *child_sa;
iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
while (iterator->iterate(iterator, (void**)&child_sa))
{
spi = child_sa->get_spi(child_sa, TRUE);
switch (child_sa->get_protocol(child_sa))
{
case PROTO_ESP:
if (esp == NULL)
{
esp = delete_payload_create(PROTO_ESP);
message->add_payload(message, (payload_t*)esp);
}
esp->add_spi(esp, spi);
break;
case PROTO_AH:
if (ah == NULL)
{
ah = delete_payload_create(PROTO_AH);
message->add_payload(message, (payload_t*)ah);
}
ah->add_spi(ah, spi);
break;
default:
break;
}
child_sa->set_state(child_sa, CHILD_DELETING);
}
iterator->destroy(iterator);
}
/**
* read in payloads and find the children to delete
*/
static void process_payloads(private_child_delete_t *this, message_t *message)
{
iterator_t *payloads, *spis;
payload_t *payload;
delete_payload_t *delete_payload;
u_int32_t spi;
protocol_id_t protocol;
child_sa_t *child_sa;
payloads = message->get_payload_iterator(message);
while (payloads->iterate(payloads, (void**)&payload))
{
if (payload->get_type(payload) == DELETE)
{
delete_payload = (delete_payload_t*)payload;
protocol = delete_payload->get_protocol_id(delete_payload);
if (protocol != PROTO_ESP && protocol != PROTO_AH)
{
continue;
}
spis = delete_payload->create_spi_iterator(delete_payload);
while (spis->iterate(spis, (void**)&spi))
{
child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol,
spi, FALSE);
if (child_sa == NULL)
{
DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI 0x%x, "
"but no such SA", protocol_id_names, protocol, ntohl(spi));
break;
}
if (child_sa->get_state(child_sa) == CHILD_REKEYING)
{
/* TODO: handle rekeying */
}
this->child_sas->insert_last(this->child_sas, child_sa);
}
spis->destroy(spis);
}
}
payloads->destroy(payloads);
}
/**
* destroy the children listed in this->child_sas
*/
static void destroy_children(private_child_delete_t *this)
{
iterator_t *iterator;
child_sa_t *child_sa;
protocol_id_t protocol;
u_int32_t spi;
iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
while (iterator->iterate(iterator, (void**)&child_sa))
{
/* TODO: can we do this more cleanly? */
spi = child_sa->get_spi(child_sa, TRUE);
protocol = child_sa->get_protocol(child_sa);
this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi);
}
iterator->destroy(iterator);
}
/**
* Implementation of task_t.build for initiator
*/
static status_t build_i(private_child_delete_t *this, message_t *message)
{
build_payloads(this, message);
return NEED_MORE;
}
/**
* Implementation of task_t.process for initiator
*/
static status_t process_i(private_child_delete_t *this, message_t *message)
{
/* flush the list before adding new SAs */
this->child_sas->destroy(this->child_sas);
this->child_sas = linked_list_create();
process_payloads(this, message);
destroy_children(this);
return SUCCESS;
}
/**
* Implementation of task_t.process for initiator
*/
static status_t process_r(private_child_delete_t *this, message_t *message)
{
process_payloads(this, message);
return NEED_MORE;
}
/**
* Implementation of task_t.build for responder
*/
static status_t build_r(private_child_delete_t *this, message_t *message)
{
build_payloads(this, message);
destroy_children(this);
return SUCCESS;
}
/**
* Implementation of task_t.get_type
*/
static task_type_t get_type(private_child_delete_t *this)
{
return CHILD_DELETE;
}
/**
* Implementation of task_t.migrate
*/
static void migrate(private_child_delete_t *this, ike_sa_t *ike_sa)
{
this->ike_sa = ike_sa;
this->child_sas->destroy(this->child_sas);
this->child_sas = linked_list_create();
}
/**
* Implementation of task_t.destroy
*/
static void destroy(private_child_delete_t *this)
{
this->child_sas->destroy(this->child_sas);
free(this);
}
/*
* Described in header.
*/
child_delete_t *child_delete_create(ike_sa_t *ike_sa, child_sa_t *child_sa)
{
private_child_delete_t *this = malloc_thing(private_child_delete_t);
this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
this->public.task.destroy = (void(*)(task_t*))destroy;
this->ike_sa = ike_sa;
this->child_sas = linked_list_create();
if (child_sa != NULL)
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
this->initiator = TRUE;
this->child_sas->insert_last(this->child_sas, child_sa);
}
else
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
this->initiator = FALSE;
}
return &this->public;
}
+58
View File
@@ -0,0 +1,58 @@
/**
* @file child_delete.h
*
* @brief Interface child_delete_t.
*
*/
/*
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef CHILD_DELETE_H_
#define CHILD_DELETE_H_
typedef struct child_delete_t child_delete_t;
#include <library.h>
#include <sa/ike_sa.h>
#include <sa/tasks/task.h>
#include <sa/child_sa.h>
/**
* @brief Task of type child_delete, delete a CHILD_SA.
*
* @b Constructors:
* - child_delete_create()
*
* @ingroup tasks
*/
struct child_delete_t {
/**
* Implements the task_t interface
*/
task_t task;
};
/**
* @brief Create a new child_delete task.
*
* @param ike_sa IKE_SA this task works for
* @param child_sa CHILD_SA to delete, or NULL as responder
* @return child_delete task to handle by the task_manager
*/
child_delete_t *child_delete_create(ike_sa_t *ike_sa, child_sa_t *child_sa);
#endif /* CHILD_DELETE_H_ */
+353
View File
@@ -0,0 +1,353 @@
/**
* @file child_rekey.c
*
* @brief Implementation of the child_rekey task.
*
*/
/*
* Copyright (C) 2005-2007 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "child_rekey.h"
#include <daemon.h>
#include <crypto/diffie_hellman.h>
#include <encoding/payloads/notify_payload.h>
#include <encoding/payloads/nonce_payload.h>
#include <sa/tasks/child_create.h>
typedef struct private_child_rekey_t private_child_rekey_t;
/**
* Private members of a child_rekey_t task.
*/
struct private_child_rekey_t {
/**
* Public methods and task_t interface.
*/
child_rekey_t public;
/**
* Assigned IKE_SA.
*/
ike_sa_t *ike_sa;
/**
* Are we the initiator?
*/
bool initiator;
/**
* the CHILD_CREATE task which is reused to simplify rekeying
*/
child_create_t *child_create;
/**
* CHILD_SA which gets rekeyed
*/
child_sa_t *child_sa;
/**
* redundandt CHILD_SA created simultaneously
*/
child_sa_t *simultaneous;
/**
* the lowest nonce compared so far
*/
chunk_t nonce;
/**
* TRUE if we have the lower nonce
*/
bool winner;
};
/**
* get the nonce from a message, return TRUE if it was lower than this->nonce
*/
static bool get_nonce(private_child_rekey_t *this, message_t *message)
{
nonce_payload_t *payload;
chunk_t nonce;
payload = (nonce_payload_t*)message->get_payload(message, NONCE);
if (payload == NULL)
{
return FALSE;
}
nonce = payload->get_nonce(payload);
if (this->nonce.ptr && memcmp(nonce.ptr, this->nonce.ptr,
min(nonce.len, this->nonce.len)) > 0)
{
chunk_free(&nonce);
return FALSE;
}
chunk_free(&this->nonce);
this->nonce = nonce;
return TRUE;
}
/**
* find a child using the REKEY_SA notify
*/
static void find_child(private_child_rekey_t *this, message_t *message)
{
iterator_t *iterator;
payload_t *payload;
iterator = message->get_payload_iterator(message);
while (iterator->iterate(iterator, (void**)&payload))
{
notify_payload_t *notify;
u_int32_t spi;
protocol_id_t protocol;
if (payload->get_type(payload) != NOTIFY)
{
continue;
}
notify = (notify_payload_t*)payload;
protocol = notify->get_protocol_id(notify);
spi = notify->get_spi(notify);
if (protocol != PROTO_ESP && protocol != PROTO_AH)
{
continue;
}
this->child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol,
spi, FALSE);
break;
}
iterator->destroy(iterator);
}
#if 0
/**
* handle a detected simultaneous rekeying situation as responder
*/
static void simultaneous_r(private_child_rekey_t *this, message_t *message)
{
private_child_rekey_t *other = NULL;
task_t *task;
iterator_t *iterator;
this->ike_sa->create_task_iterator(this->ike_sa);
while (iterator->iterate(iterator, (void**)&task))
{
if (task->get_type(task) == CHILD_REKEY)
{
other = (private_child_rekey_t*)task;
break;
}
}
iterator->destroy(iterator);
if (other)
{
other->simultaneous = this->child_create->get_child(this->child_create);
if (!get_nonce(other, message))
{
/* this wins the race, other lost */
other->winner = FALSE;
}
}
}
/**
* was there a simultaneous rekeying, did we win the nonce compare?
*/
static bool simultaneous_i(private_child_rekey_t *this, message_t *message)
{
if (this->winner || get_nonce(this, message))
{
/* we have the lower nonce and win */
return TRUE;
}
return FALSE;
}
#endif
/**
* Implementation of task_t.build for initiator
*/
static status_t build_i(private_child_rekey_t *this, message_t *message)
{
notify_payload_t *notify;
protocol_id_t protocol;
u_int32_t spi, reqid;
/* our CHILD_CREATE task does the hard work for us... */
reqid = this->child_sa->get_reqid(this->child_sa);
this->child_create->use_reqid(this->child_create, reqid);
this->child_create->task.build(&this->child_create->task, message);
get_nonce(this, message);
/* ... we just need the rekey notify */
protocol = this->child_sa->get_protocol(this->child_sa);
spi = this->child_sa->get_spi(this->child_sa, TRUE);
notify = notify_payload_create_from_protocol_and_type(protocol, REKEY_SA);
notify->set_spi(notify, spi);
message->add_payload(message, (payload_t*)notify);
this->child_sa->set_state(this->child_sa, CHILD_REKEYING);
return NEED_MORE;
}
/**
* Implementation of task_t.process for initiator
*/
static status_t process_r(private_child_rekey_t *this, message_t *message)
{
/* let the CHILD_CREATE task process the message */
this->child_create->task.process(&this->child_create->task, message);
get_nonce(this, message);
find_child(this, message);
return NEED_MORE;
}
/**
* Implementation of task_t.build for responder
*/
static status_t build_r(private_child_rekey_t *this, message_t *message)
{
u_int32_t reqid;
if (this->child_sa == NULL ||
this->child_sa->get_state(this->child_sa) == CHILD_DELETING)
{
message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty);
return SUCCESS;
}
/* let the CHILD_CREATE task build the response */
reqid = this->child_sa->get_reqid(this->child_sa);
this->child_create->use_reqid(this->child_create, reqid);
this->child_create->task.build(&this->child_create->task, message);
get_nonce(this, message);
if (this->child_sa->get_state(this->child_sa) == CHILD_REKEYING)
{
/* simultaneous_detected(this); */
}
this->child_sa->set_state(this->child_sa, CHILD_REKEYING);
return SUCCESS;
}
/**
* Implementation of task_t.process for initiator
*/
static status_t process_i(private_child_rekey_t *this, message_t *message)
{
protocol_id_t protocol;
u_int32_t spi;
this->child_create->task.process(&this->child_create->task, message);
/*if (!simultaneous_won(this, message))
{
* delete the redundant CHILD_SA, instead of the rekeyed *
this->child_sa = this->create_child->get_child(this->create_child);
}*/
spi = this->child_sa->get_spi(this->child_sa, TRUE);
protocol = this->child_sa->get_protocol(this->child_sa);
/* TODO: don't delete when rekeying failed */
if (this->ike_sa->delete_child_sa(this->ike_sa, protocol, spi) != SUCCESS)
{
return FAILED;
}
return SUCCESS;
}
/**
* Implementation of task_t.get_type
*/
static task_type_t get_type(private_child_rekey_t *this)
{
return CHILD_REKEY;
}
/**
* Implementation of task_t.migrate
*/
static void migrate(private_child_rekey_t *this, ike_sa_t *ike_sa)
{
this->child_create->task.migrate(&this->child_create->task, ike_sa);
chunk_free(&this->nonce);
this->ike_sa = ike_sa;
this->winner = TRUE;
this->simultaneous = NULL;
}
/**
* Implementation of task_t.destroy
*/
static void destroy(private_child_rekey_t *this)
{
this->child_create->task.destroy(&this->child_create->task);
chunk_free(&this->nonce);
free(this);
}
/*
* Described in header.
*/
child_rekey_t *child_rekey_create(ike_sa_t *ike_sa, child_sa_t *child_sa)
{
private_child_rekey_t *this = malloc_thing(private_child_rekey_t);
policy_t *policy;
this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
this->public.task.destroy = (void(*)(task_t*))destroy;
if (child_sa != NULL)
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
this->initiator = TRUE;
policy = child_sa->get_policy(child_sa);
this->child_create = child_create_create(ike_sa, policy);
}
else
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
this->initiator = FALSE;
this->child_create = child_create_create(ike_sa, NULL);
}
this->ike_sa = ike_sa;
this->child_sa = child_sa;
this->nonce = chunk_empty;
this->winner = TRUE;
this->simultaneous = NULL;
return &this->public;
}
+58
View File
@@ -0,0 +1,58 @@
/**
* @file child_rekey.h
*
* @brief Interface child_rekey_t.
*
*/
/*
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef CHILD_REKEY_H_
#define CHILD_REKEY_H_
typedef struct child_rekey_t child_rekey_t;
#include <library.h>
#include <sa/ike_sa.h>
#include <sa/child_sa.h>
#include <sa/tasks/task.h>
/**
* @brief Task of type CHILD_REKEY, rekey an established CHILD_SA.
*
* @b Constructors:
* - child_rekey_create()
*
* @ingroup tasks
*/
struct child_rekey_t {
/**
* Implements the task_t interface
*/
task_t task;
};
/**
* @brief Create a new CHILD_REKEY task.
*
* @param ike_sa IKE_SA this task works for
* @param child_sa child_sa to rekey, NULL if responder
* @return child_rekey task to handle by the task_manager
*/
child_rekey_t *child_rekey_create(ike_sa_t *ike_sa, child_sa_t *child_sa);
#endif /* CHILD_REKEY_H_ */
+513
View File
@@ -0,0 +1,513 @@
/**
* @file ike_auth.c
*
* @brief Implementation of the ike_auth task.
*
*/
/*
* Copyright (C) 2005-2007 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "ike_auth.h"
#include <string.h>
#include <daemon.h>
#include <crypto/diffie_hellman.h>
#include <encoding/payloads/id_payload.h>
#include <encoding/payloads/auth_payload.h>
#include <encoding/payloads/nonce_payload.h>
typedef struct private_ike_auth_t private_ike_auth_t;
/**
* Private members of a ike_auth_t task.
*/
struct private_ike_auth_t {
/**
* Public methods and task_t interface.
*/
ike_auth_t public;
/**
* Assigned IKE_SA.
*/
ike_sa_t *ike_sa;
/**
* Are we the initiator?
*/
bool initiator;
/**
* Nonce chosen by us in ike_init
*/
chunk_t my_nonce;
/**
* Nonce chosen by peer in ike_init
*/
chunk_t other_nonce;
/**
* IKE_SA_INIT message sent by us
*/
packet_t *my_packet;
/**
* IKE_SA_INIT message sent by peer
*/
packet_t *other_packet;
/**
* authenticator to authenticate us
*/
authenticator_t *my_auth;
/**
* authenticator to authenticate peer
*/
authenticator_t *other_auth;
/**
* has the peer been authenticated successfully?
*/
bool peer_authenticated;
};
/**
* build the payloads for the message
*/
static status_t build_payloads(private_ike_auth_t *this, message_t *message)
{
authenticator_t *auth;
auth_payload_t *auth_payload;
id_payload_t *id_payload;
chunk_t ike_sa_init;
identification_t *me, *other;
policy_t *policy;
auth_method_t method = AUTH_RSA;
status_t status;
/* add own ID payload */
me = this->ike_sa->get_my_id(this->ike_sa);
other = this->ike_sa->get_other_id(this->ike_sa);
id_payload = id_payload_create_from_identification(this->initiator, me);
message->add_payload(message, (payload_t*)id_payload);
/* as initiator, include other ID if it does not contain wildcards */
if (this->initiator && !other->contains_wildcards(other))
{
id_payload = id_payload_create_from_identification(FALSE, other);
message->add_payload(message, (payload_t*)id_payload);
}
/* create own authenticator and add auth payload */
policy = this->ike_sa->get_policy(this->ike_sa);
if (policy)
{
method = policy->get_auth_method(policy);
}
auth = authenticator_create(this->ike_sa, method);
if (auth == NULL)
{
SIG(IKE_UP_FAILED, "configured authentication method %N not supported",
auth_method_names, method);
return FAILED;
}
ike_sa_init = this->my_packet->get_data(this->my_packet);
status = auth->build(auth, ike_sa_init, this->other_nonce, &auth_payload);
auth->destroy(auth);
if (status != SUCCESS)
{
SIG(IKE_UP_FAILED, "generating authentication data failed");
return FAILED;
}
message->add_payload(message, (payload_t*)auth_payload);
return SUCCESS;
}
/**
* process payloads from message
*/
static void process_payloads(private_ike_auth_t *this, message_t *message)
{
iterator_t *iterator;
payload_t *payload;
payload_type_t type;
identification_t *idi = NULL, *idr = NULL;
auth_payload_t *auth_payload = NULL;
authenticator_t *auth;
auth_method_t auth_method;
status_t status;
iterator = message->get_payload_iterator(message);
while (iterator->iterate(iterator, (void**)&payload))
{
type = payload->get_type(payload);
switch (type)
{
case ID_INITIATOR:
{
id_payload_t *id_payload = (id_payload_t*)payload;
idi = id_payload->get_identification(id_payload);
break;
}
case ID_RESPONDER:
{
id_payload_t *id_payload = (id_payload_t*)payload;
idr = id_payload->get_identification(id_payload);
break;
}
case AUTHENTICATION:
{
auth_payload = (auth_payload_t*)payload;
break;
}
default:
break;
}
}
iterator->destroy(iterator);
/* apply IDs */
if ((this->initiator && idr == NULL) || (!this->initiator && idi == NULL))
{
SIG(IKE_UP_FAILED, "ID payload missing in message");
DESTROY_IF(idr); DESTROY_IF(idi);
return;
}
if (this->initiator)
{
identification_t *other_id = this->ike_sa->get_other_id(this->ike_sa);
if (!idr->matches(idr, other_id, NULL))
{
SIG(IKE_UP_FAILED, "received inacceptable id %D, %D required", idr,
this->ike_sa->get_other_id(this->ike_sa));
DESTROY_IF(idi); DESTROY_IF(idr);
return;
}
this->ike_sa->set_other_id(this->ike_sa, idr);
}
else
{
identification_t *my_id = this->ike_sa->get_other_id(this->ike_sa);
if (idr)
{
if (!idr->matches(idr, my_id, NULL))
{
SIG(IKE_UP_FAILED, "received inacceptable id %D, %D required",
idr, this->ike_sa->get_other_id(this->ike_sa));
DESTROY_IF(idi); DESTROY_IF(idr);
return;
}
this->ike_sa->set_my_id(this->ike_sa, idr);
}
else
{
if (my_id->contains_wildcards(my_id))
{
SIG(IKE_UP_FAILED, "own ID (%D) not defined after exchange",
my_id);
DESTROY_IF(idi);
return;
}
}
this->ike_sa->set_other_id(this->ike_sa, idi);
}
/* verify auth payload */
if (auth_payload == NULL)
{
SIG(IKE_UP_FAILED, "AUTH payload missing in message");
return;
}
auth_method = auth_payload->get_auth_method(auth_payload);
auth = authenticator_create(this->ike_sa, auth_method);
if (auth == NULL)
{
SIG(IKE_UP_FAILED, "authentication method %N used by %D not "
"supported", auth_method_names, auth_method,
this->ike_sa->get_other_id(this->ike_sa));
return;
}
status = auth->verify(auth, this->other_packet->get_data(this->other_packet),
this->my_nonce, auth_payload);
auth->destroy(auth);
if (status != SUCCESS)
{
SIG(IKE_UP_FAILED, "authentication of %D using %N failed",
this->ike_sa->get_other_id(this->ike_sa),
auth_method_names, auth_method);
return;
}
this->peer_authenticated = TRUE;
}
/**
* collect the needed information in the IKE_SA_INIT exchange from our message
*/
static status_t collect_my_init_data(private_ike_auth_t *this, message_t *message)
{
nonce_payload_t *nonce;
/* get the nonce that was generated in ike_init */
nonce = (nonce_payload_t*)message->get_payload(message, NONCE);
if (nonce == NULL)
{
return FAILED;
}
this->my_nonce = nonce->get_nonce(nonce);
/* pre-generate the message, so we can store it for us */
if (this->ike_sa->generate_message(this->ike_sa, message,
&this->my_packet) != SUCCESS)
{
return FAILED;
}
return NEED_MORE;
}
/**
* collect the needed information in the IKE_SA_INIT exchange from others message
*/
static status_t collect_other_init_data(private_ike_auth_t *this, message_t *message)
{
/* we collect the needed information in the IKE_SA_INIT exchange */
nonce_payload_t *nonce;
/* get the nonce that was generated in ike_init */
nonce = (nonce_payload_t*)message->get_payload(message, NONCE);
if (nonce == NULL)
{
return FAILED;
}
this->other_nonce = nonce->get_nonce(nonce);
/* pre-generate the message, so we can store it for us */
this->other_packet = message->get_packet(message);
return NEED_MORE;
}
/**
* Implementation of task_t.build for initiator
*/
static status_t build_i(private_ike_auth_t *this, message_t *message)
{
if (message->get_exchange_type(message) == IKE_SA_INIT)
{
return collect_my_init_data(this, message);
}
if (build_payloads(this, message) == SUCCESS)
{
return NEED_MORE;
}
return FAILED;
}
/**
* Implementation of task_t.process for initiator
*/
static status_t process_r(private_ike_auth_t *this, message_t *message)
{
if (message->get_exchange_type(message) == IKE_SA_INIT)
{
return collect_other_init_data(this, message);
}
process_payloads(this, message);
return NEED_MORE;
}
/**
* Implementation of task_t.build for responder
*/
static status_t build_r(private_ike_auth_t *this, message_t *message)
{
if (message->get_exchange_type(message) == IKE_SA_INIT)
{
return collect_my_init_data(this, message);
}
if (!this->peer_authenticated)
{
message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty);
return FAILED;
}
if (build_payloads(this, message) == SUCCESS)
{
this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
SIG(IKE_UP_SUCCESS, "IKE_SA established between %D[%H]...[%H]%D",
this->ike_sa->get_my_id(this->ike_sa),
this->ike_sa->get_my_host(this->ike_sa),
this->ike_sa->get_other_host(this->ike_sa),
this->ike_sa->get_other_id(this->ike_sa));
return SUCCESS;
}
return FAILED;
}
/**
* Implementation of task_t.process for initiator
*/
static status_t process_i(private_ike_auth_t *this, message_t *message)
{
iterator_t *iterator;
payload_t *payload;
if (message->get_exchange_type(message) == IKE_SA_INIT)
{
return collect_other_init_data(this, message);
}
iterator = message->get_payload_iterator(message);
while (iterator->iterate(iterator, (void**)&payload))
{
if (payload->get_type(payload) == NOTIFY)
{
notify_payload_t *notify = (notify_payload_t*)payload;
notify_type_t type = notify->get_notify_type(notify);
switch (type)
{
case NO_PROPOSAL_CHOSEN:
case SINGLE_PAIR_REQUIRED:
case NO_ADDITIONAL_SAS:
case INTERNAL_ADDRESS_FAILURE:
case FAILED_CP_REQUIRED:
case TS_UNACCEPTABLE:
case INVALID_SELECTORS:
/* these are errors, but are not critical as only the
* CHILD_SA won't get build, but IKE_SA establishes anyway */
DBG1(DBG_IKE, "received %N notify, no CHILD_SA built",
notify_type_names, type);
iterator->destroy(iterator);
return SUCCESS;
default:
{
if (type < 16383)
{
DBG1(DBG_IKE, "received %N notify error",
notify_type_names, type);
iterator->destroy(iterator);
return FAILED;
}
}
}
}
}
iterator->destroy(iterator);
process_payloads(this, message);
if (this->peer_authenticated)
{
this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
SIG(IKE_UP_SUCCESS, "IKE_SA established between %D[%H]...[%H]%D",
this->ike_sa->get_my_id(this->ike_sa),
this->ike_sa->get_my_host(this->ike_sa),
this->ike_sa->get_other_host(this->ike_sa),
this->ike_sa->get_other_id(this->ike_sa));
return SUCCESS;
}
return FAILED;
}
/**
* Implementation of task_t.get_type
*/
static task_type_t get_type(private_ike_auth_t *this)
{
return IKE_AUTHENTICATE;
}
/**
* Implementation of task_t.migrate
*/
static void migrate(private_ike_auth_t *this, ike_sa_t *ike_sa)
{
chunk_free(&this->my_nonce);
chunk_free(&this->other_nonce);
DESTROY_IF(this->my_packet);
DESTROY_IF(this->other_packet);
DESTROY_IF(this->my_auth);
DESTROY_IF(this->other_auth);
this->my_packet = NULL;
this->other_packet = NULL;
this->my_auth = NULL;
this->other_auth = NULL;
this->peer_authenticated = FALSE;
this->ike_sa = ike_sa;
}
/**
* Implementation of task_t.destroy
*/
static void destroy(private_ike_auth_t *this)
{
chunk_free(&this->my_nonce);
chunk_free(&this->other_nonce);
DESTROY_IF(this->my_packet);
DESTROY_IF(this->other_packet);
DESTROY_IF(this->my_auth);
DESTROY_IF(this->other_auth);
free(this);
}
/*
* Described in header.
*/
ike_auth_t *ike_auth_create(ike_sa_t *ike_sa, bool initiator)
{
private_ike_auth_t *this = malloc_thing(private_ike_auth_t);
this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
this->public.task.destroy = (void(*)(task_t*))destroy;
if (initiator)
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
}
else
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
}
this->ike_sa = ike_sa;
this->initiator = initiator;
this->my_nonce = chunk_empty;
this->other_nonce = chunk_empty;
this->my_packet = NULL;
this->other_packet = NULL;
this->my_auth = NULL;
this->other_auth = NULL;
this->peer_authenticated = FALSE;
return &this->public;
}
+60
View File
@@ -0,0 +1,60 @@
/**
* @file ike_auth.h
*
* @brief Interface ike_auth_t.
*
*/
/*
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef IKE_AUTH_H_
#define IKE_AUTH_H_
typedef struct ike_auth_t ike_auth_t;
#include <library.h>
#include <sa/ike_sa.h>
#include <sa/tasks/task.h>
/**
* @brief Task of type ike_auth, authenticates an IKE_SA authenticators.
*
* The ike_auth task authenticates the IKE_SA using the IKE_AUTH
* exchange.
*
* @b Constructors:
* - ike_auth_create()
*
* @ingroup tasks
*/
struct ike_auth_t {
/**
* Implements the task_t interface
*/
task_t task;
};
/**
* @brief Create a new task of type IKE_AUTHENTICATE.
*
* @param ike_sa IKE_SA this task works for
* @param initiator TRUE if thask is the initator of an exchange
* @return ike_auth task to handle by the task_manager
*/
ike_auth_t *ike_auth_create(ike_sa_t *ike_sa, bool initiator);
#endif /* IKE_AUTH_H_ */
+361
View File
@@ -0,0 +1,361 @@
/**
* @file ike_cert.c
*
* @brief Implementation of the ike_cert task.
*
*/
/*
* Copyright (C) 2006-2007 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "ike_cert.h"
#include <daemon.h>
#include <sa/ike_sa.h>
#include <crypto/hashers/hasher.h>
#include <encoding/payloads/cert_payload.h>
#include <encoding/payloads/certreq_payload.h>
typedef struct private_ike_cert_t private_ike_cert_t;
/**
* Private members of a ike_cert_t task.
*/
struct private_ike_cert_t {
/**
* Public methods and task_t interface.
*/
ike_cert_t public;
/**
* Assigned IKE_SA.
*/
ike_sa_t *ike_sa;
/**
* Are we the initiator?
*/
bool initiator;
/**
* list of CA cert hashes requested, items point to 20 byte chunk
*/
linked_list_t *cas;
};
/**
* read certificate requests
*/
static void process_certreqs(private_ike_cert_t *this, message_t *message)
{
iterator_t *iterator;
payload_t *payload;
iterator = message->get_payload_iterator(message);
while (iterator->iterate(iterator, (void**)&payload))
{
if (payload->get_type(payload) == CERTIFICATE_REQUEST)
{
certreq_payload_t *certreq = (certreq_payload_t*)payload;
cert_encoding_t encoding;
chunk_t keyids, keyid;
encoding = certreq->get_cert_encoding(certreq);
if (encoding != CERT_X509_SIGNATURE)
{
DBG1(DBG_IKE, "certreq payload %N not supported, ignored",
cert_encoding_names, encoding);
continue;
}
keyids = certreq->get_data(certreq);
while (keyids.len >= HASH_SIZE_SHA1)
{
keyid = chunk_create(keyids.ptr, HASH_SIZE_SHA1);
keyid = chunk_clone(keyid);
this->cas->insert_last(this->cas, keyid.ptr);
keyids = chunk_skip(keyids, HASH_SIZE_SHA1);
}
}
}
iterator->destroy(iterator);
}
/**
* import certificates
*/
static void process_certs(private_ike_cert_t *this, message_t *message)
{
iterator_t *iterator;
payload_t *payload;
iterator = message->get_payload_iterator(message);
while (iterator->iterate(iterator, (void**)&payload))
{
if (payload->get_type(payload) == CERTIFICATE)
{
cert_encoding_t encoding;
x509_t *cert;
chunk_t cert_data;
bool found;
cert_payload_t *cert_payload = (cert_payload_t*)payload;
encoding = cert_payload->get_cert_encoding(cert_payload);
if (encoding != CERT_X509_SIGNATURE)
{
DBG1(DBG_IKE, "certificate payload %N not supported, ignored",
cert_encoding_names, encoding);
continue;
}
cert_data = cert_payload->get_data_clone(cert_payload);
cert = x509_create_from_chunk(cert_data);
if (cert)
{
if (charon->credentials->verify(charon->credentials,
cert, &found))
{
DBG2(DBG_IKE, "received end entity certificate is trusted, "
"added to store");
if (!found)
{
charon->credentials->add_end_certificate(
charon->credentials, cert);
}
else
{
cert->destroy(cert);
}
}
else
{
DBG1(DBG_IKE, "received end entity certificate is not "
"trusted, discarded");
cert->destroy(cert);
}
}
else
{
DBG1(DBG_IKE, "parsing of received certificate failed, discarded");
chunk_free(&cert_data);
}
}
}
iterator->destroy(iterator);
}
/**
* build certificate requests
*/
static void build_certreqs(private_ike_cert_t *this, message_t *message)
{
connection_t *connection;
policy_t *policy;
identification_t *ca;
certreq_payload_t *certreq;
connection = this->ike_sa->get_connection(this->ike_sa);
if (connection->get_certreq_policy(connection) != CERT_NEVER_SEND)
{
policy = this->ike_sa->get_policy(this->ike_sa);
if (policy)
{
ca = policy->get_other_ca(policy);
if (ca && ca->get_type(ca) != ID_ANY)
{
certreq = certreq_payload_create_from_cacert(ca);
}
else
{
certreq = certreq_payload_create_from_cacerts();
}
}
else
{
certreq = certreq_payload_create_from_cacerts();
}
if (certreq)
{
message->add_payload(message, (payload_t*)certreq);
}
}
}
/**
* add certificates to message
*/
static void build_certs(private_ike_cert_t *this, message_t *message)
{
policy_t *policy;
connection_t *connection;
x509_t *cert;
cert_payload_t *payload;
policy = this->ike_sa->get_policy(this->ike_sa);
connection = this->ike_sa->get_connection(this->ike_sa);
if (policy && policy->get_auth_method(policy) == AUTH_RSA)
{
switch (connection->get_cert_policy(connection))
{
case CERT_NEVER_SEND:
break;
case CERT_SEND_IF_ASKED:
if (this->cas->get_count(this->cas) == 0)
{
break;
}
/* FALL */
case CERT_ALWAYS_SEND:
{
/* TODO: respect CA cert request */
cert = charon->credentials->get_certificate(charon->credentials,
policy->get_my_id(policy));
if (cert)
{
payload = cert_payload_create_from_x509(cert);
message->add_payload(message, (payload_t*)payload);
}
}
}
}
}
/**
* Implementation of task_t.process for initiator
*/
static status_t build_i(private_ike_cert_t *this, message_t *message)
{
if (message->get_exchange_type(message) == IKE_SA_INIT)
{
return NEED_MORE;
}
build_certreqs(this, message);
build_certs(this, message);
return NEED_MORE;
}
/**
* Implementation of task_t.process for responder
*/
static status_t process_r(private_ike_cert_t *this, message_t *message)
{
if (message->get_exchange_type(message) == IKE_SA_INIT)
{
return NEED_MORE;
}
process_certreqs(this, message);
process_certs(this, message);
return NEED_MORE;
}
/**
* Implementation of task_t.build for responder
*/
static status_t build_r(private_ike_cert_t *this, message_t *message)
{
if (message->get_exchange_type(message) == IKE_SA_INIT)
{
build_certreqs(this, message);
return NEED_MORE;
}
build_certs(this, message);
return SUCCESS;
}
/**
* Implementation of task_t.process for initiator
*/
static status_t process_i(private_ike_cert_t *this, message_t *message)
{
if (message->get_exchange_type(message) == IKE_SA_INIT)
{
process_certreqs(this, message);
return NEED_MORE;
}
process_certs(this, message);
return SUCCESS;
}
/**
* Implementation of task_t.get_type
*/
static task_type_t get_type(private_ike_cert_t *this)
{
return IKE_CERT;
}
/**
* Implementation of task_t.migrate
*/
static void migrate(private_ike_cert_t *this, ike_sa_t *ike_sa)
{
this->ike_sa = ike_sa;
this->cas->destroy_function(this->cas, free);
this->cas = linked_list_create();
}
/**
* Implementation of task_t.destroy
*/
static void destroy(private_ike_cert_t *this)
{
this->cas->destroy_function(this->cas, free);
free(this);
}
/*
* Described in header.
*/
ike_cert_t *ike_cert_create(ike_sa_t *ike_sa, bool initiator)
{
private_ike_cert_t *this = malloc_thing(private_ike_cert_t);
this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
this->public.task.destroy = (void(*)(task_t*))destroy;
if (initiator)
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
}
else
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
}
this->ike_sa = ike_sa;
this->initiator = initiator;
this->cas = linked_list_create();
return &this->public;
}
+61
View File
@@ -0,0 +1,61 @@
/**
* @file ike_cert.h
*
* @brief Interface ike_cert_t.
*
*/
/*
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef IKE_CERT_H_
#define IKE_CERT_H_
typedef struct ike_cert_t ike_cert_t;
#include <library.h>
#include <sa/ike_sa.h>
#include <sa/tasks/task.h>
/**
* @brief Task of type ike_cert, exchanges certificates and
* certificate requests.
*
* @b Constructors:
* - ike_cert_create()
*
* @ingroup tasks
*/
struct ike_cert_t {
/**
* Implements the task_t interface
*/
task_t task;
};
/**
* @brief Create a new ike_cert task.
*
* The initiator parameter means the original initiator, not the initiator
* of the certificate request.
*
* @param ike_sa IKE_SA this task works for
* @param initiator TRUE if thask is the original initator
* @return ike_cert task to handle by the task_manager
*/
ike_cert_t *ike_cert_create(ike_sa_t *ike_sa, bool initiator);
#endif /* IKE_CERT_H_ */
+421
View File
@@ -0,0 +1,421 @@
/**
* @file ike_config.c
*
* @brief Implementation of the ike_config task.
*
*/
/*
* Copyright (C) 2007 Martin Willi
* Copyright (C) 2006-2007 Fabian Hartmann, Noah Heusser
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "ike_config.h"
#include <daemon.h>
#include <encoding/payloads/cp_payload.h>
typedef struct private_ike_config_t private_ike_config_t;
/**
* Private members of a ike_config_t task.
*/
struct private_ike_config_t {
/**
* Public methods and task_t interface.
*/
ike_config_t public;
/**
* Assigned IKE_SA.
*/
ike_sa_t *ike_sa;
/**
* Are we the initiator?
*/
bool initiator;
/**
* associated policy with virtual IP configuration
*/
policy_t *policy;
/**
* virtual ip
*/
host_t *virtual_ip;
/**
* list of DNS servers
*/
linked_list_t *dns;
};
/**
* build configuration payloads and attributes
*/
static void build_payloads(private_ike_config_t *this, message_t *message,
config_type_t type)
{
cp_payload_t *cp;
configuration_attribute_t *ca;
chunk_t chunk, prefix;
if (!this->virtual_ip)
{
return;
}
cp = cp_payload_create();
cp->set_config_type(cp, type);
ca = configuration_attribute_create();
if (this->virtual_ip->get_family(this->virtual_ip) == AF_INET)
{
ca->set_type(ca, INTERNAL_IP4_ADDRESS);
if (this->virtual_ip->is_anyaddr(this->virtual_ip))
{
chunk = chunk_empty;
}
else
{
chunk = this->virtual_ip->get_address(this->virtual_ip);
}
}
else
{
ca->set_type(ca, INTERNAL_IP6_ADDRESS);
if (this->virtual_ip->is_anyaddr(this->virtual_ip))
{
chunk = chunk_empty;
}
else
{
prefix = chunk_alloca(1);
*prefix.ptr = 64;
chunk = this->virtual_ip->get_address(this->virtual_ip);
chunk = chunk_cata("cc", chunk, prefix);
}
}
ca->set_value(ca, chunk);
cp->add_configuration_attribute(cp, ca);
/* we currently always add a DNS request if we request an IP */
if (this->initiator)
{
ca = configuration_attribute_create();
if (this->virtual_ip->get_family(this->virtual_ip) == AF_INET)
{
ca->set_type(ca, INTERNAL_IP4_DNS);
}
else
{
ca->set_type(ca, INTERNAL_IP6_DNS);
}
cp->add_configuration_attribute(cp, ca);
}
else
{
host_t *ip;
iterator_t *iterator = this->dns->create_iterator(this->dns, TRUE);
while (iterator->iterate(iterator, (void**)&ip))
{
ca = configuration_attribute_create();
if (ip->get_family(ip) == AF_INET)
{
ca->set_type(ca, INTERNAL_IP4_DNS);
}
else
{
ca->set_type(ca, INTERNAL_IP6_DNS);
}
chunk = ip->get_address(ip);
ca->set_value(ca, chunk);
cp->add_configuration_attribute(cp, ca);
}
iterator->destroy(iterator);
}
message->add_payload(message, (payload_t*)cp);
}
/**
* process a single configuration attribute
*/
static void process_attribute(private_ike_config_t *this,
configuration_attribute_t *ca)
{
host_t *ip;
chunk_t addr;
int family = AF_INET6;
switch (ca->get_type(ca))
{
case INTERNAL_IP4_ADDRESS:
family = AF_INET;
/* fall */
case INTERNAL_IP6_ADDRESS:
{
addr = ca->get_value(ca);
if (addr.len == 0)
{
ip = host_create_any(family);
}
else
{
/* skip prefix byte in IPv6 payload*/
if (family == AF_INET6)
{
addr.len--;
}
ip = host_create_from_chunk(family, addr, 0);
}
if (ip && !this->virtual_ip)
{
this->virtual_ip = ip;
}
break;
}
case INTERNAL_IP4_DNS:
family = AF_INET;
/* fall */
case INTERNAL_IP6_DNS:
{
addr = ca->get_value(ca);
if (addr.len == 0)
{
ip = host_create_any(family);
}
else
{
ip = host_create_from_chunk(family, addr, 0);
}
if (ip)
{
this->dns->insert_last(this->dns, ip);
}
break;
}
case INTERNAL_IP4_NBNS:
case INTERNAL_IP6_NBNS:
/* TODO */
default:
DBG1(DBG_IKE, "ignoring %N config attribute",
configuration_attribute_type_names,
ca->get_type(ca));
break;
}
}
/**
* Scan for configuration payloads and attributes
*/
static void process_payloads(private_ike_config_t *this, message_t *message)
{
iterator_t *iterator, *attributes;
payload_t *payload;
iterator = message->get_payload_iterator(message);
while (iterator->iterate(iterator, (void**)&payload))
{
if (payload->get_type(payload) == CONFIGURATION)
{
cp_payload_t *cp = (cp_payload_t*)payload;
configuration_attribute_t *ca;
switch (cp->get_config_type(cp))
{
case CFG_REQUEST:
case CFG_REPLY:
{
attributes = cp->create_attribute_iterator(cp);
while (attributes->iterate(attributes, (void**)&ca))
{
process_attribute(this, ca);
}
attributes->destroy(attributes);
break;
}
default:
DBG1(DBG_IKE, "ignoring %N config payload",
config_type_names, cp->get_config_type(cp));
break;
}
}
}
iterator->destroy(iterator);
}
/**
* Implementation of task_t.process for initiator
*/
static status_t build_i(private_ike_config_t *this, message_t *message)
{
if (message->get_exchange_type(message) != IKE_SA_INIT)
{
this->virtual_ip = this->policy->get_virtual_ip(this->policy, NULL);
build_payloads(this, message, CFG_REQUEST);
}
return NEED_MORE;
}
/**
* Implementation of task_t.process for responder
*/
static status_t process_r(private_ike_config_t *this, message_t *message)
{
if (message->get_exchange_type(message) != IKE_SA_INIT)
{
process_payloads(this, message);
}
return NEED_MORE;
}
/**
* Implementation of task_t.build for responder
*/
static status_t build_r(private_ike_config_t *this, message_t *message)
{
if (message->get_exchange_type(message) != IKE_SA_INIT)
{
this->policy = this->ike_sa->get_policy(this->ike_sa);
if (this->policy && this->virtual_ip)
{
host_t *ip;
DBG1(DBG_IKE, "peer requested virtual IP %H", this->virtual_ip);
ip = this->policy->get_virtual_ip(this->policy, this->virtual_ip);
if (ip == NULL)
{
DBG1(DBG_IKE, "not assigning a virtual IP to peer");
return SUCCESS;
}
DBG1(DBG_IKE, "assigning virtual IP %H to peer", ip);
this->ike_sa->set_virtual_ip(this->ike_sa, FALSE, ip);
this->virtual_ip->destroy(this->virtual_ip);
this->virtual_ip = ip;
/* DNS is for testing only */
if (this->dns->remove_last(this->dns, (void**)&ip) == SUCCESS)
{
ip->destroy(ip);
ip = host_create_from_string("10.3.0.1", 0);
this->dns->insert_last(this->dns, ip);
ip = host_create_from_string("10.3.0.2", 0);
this->dns->insert_last(this->dns, ip);
}
build_payloads(this, message, CFG_REPLY);
}
return SUCCESS;
}
return NEED_MORE;
}
/**
* Implementation of task_t.process for initiator
*/
static status_t process_i(private_ike_config_t *this, message_t *message)
{
if (message->get_exchange_type(message) != IKE_SA_INIT)
{
host_t *ip;
DESTROY_IF(this->virtual_ip);
this->virtual_ip = NULL;
process_payloads(this, message);
if (this->virtual_ip)
{
this->ike_sa->set_virtual_ip(this->ike_sa, TRUE, this->virtual_ip);
while (this->dns->remove_last(this->dns, (void**)&ip) == SUCCESS)
{
this->ike_sa->add_dns_server(this->ike_sa, ip);
ip->destroy(ip);
}
}
return SUCCESS;
}
return NEED_MORE;
}
/**
* Implementation of task_t.get_type
*/
static task_type_t get_type(private_ike_config_t *this)
{
return IKE_CONFIG;
}
/**
* Implementation of task_t.migrate
*/
static void migrate(private_ike_config_t *this, ike_sa_t *ike_sa)
{
DESTROY_IF(this->virtual_ip);
this->dns->destroy_offset(this->dns, offsetof(host_t, destroy));
this->ike_sa = ike_sa;
this->virtual_ip = NULL;
this->dns = linked_list_create();
}
/**
* Implementation of task_t.destroy
*/
static void destroy(private_ike_config_t *this)
{
DESTROY_IF(this->virtual_ip);
this->dns->destroy_offset(this->dns, offsetof(host_t, destroy));
free(this);
}
/*
* Described in header.
*/
ike_config_t *ike_config_create(ike_sa_t *ike_sa, policy_t *policy)
{
private_ike_config_t *this = malloc_thing(private_ike_config_t);
this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
this->public.task.destroy = (void(*)(task_t*))destroy;
if (policy)
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
this->initiator = TRUE;
}
else
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
this->initiator = FALSE;
}
this->ike_sa = ike_sa;
this->policy = policy;
this->virtual_ip = NULL;
this->dns = linked_list_create();
return &this->public;
}
+59
View File
@@ -0,0 +1,59 @@
/**
* @file ike_config.h
*
* @brief Interface ike_config_t.
*
*/
/*
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef IKE_CONFIG_H_
#define IKE_CONFIG_H_
typedef struct ike_config_t ike_config_t;
#include <library.h>
#include <sa/ike_sa.h>
#include <sa/tasks/task.h>
#include <config/policies/policy.h>
/**
* @brief Task of type IKE_CONFIG, sets up a virtual IP and other
* configurations for an IKE_SA.
*
* @b Constructors:
* - ike_config_create()
*
* @ingroup tasks
*/
struct ike_config_t {
/**
* Implements the task_t interface
*/
task_t task;
};
/**
* @brief Create a new ike_config task.
*
* @param ike_sa IKE_SA this task works for
* @param policy policy for the initiator, NULL for the responder
* @return ike_config task to handle by the task_manager
*/
ike_config_t *ike_config_create(ike_sa_t *ike_sa, policy_t *policy);
#endif /* IKE_CONFIG_H_ */
+169
View File
@@ -0,0 +1,169 @@
/**
* @file ike_delete.c
*
* @brief Implementation of the ike_delete task.
*
*/
/*
* Copyright (C) 2006-2007 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "ike_delete.h"
#include <daemon.h>
#include <encoding/payloads/delete_payload.h>
typedef struct private_ike_delete_t private_ike_delete_t;
/**
* Private members of a ike_delete_t task.
*/
struct private_ike_delete_t {
/**
* Public methods and task_t interface.
*/
ike_delete_t public;
/**
* Assigned IKE_SA.
*/
ike_sa_t *ike_sa;
/**
* Are we the initiator?
*/
bool initiator;
/**
* are we responding to a delete, but have initated our own?
*/
bool simultaneous;
};
/**
* Implementation of task_t.build for initiator
*/
static status_t build_i(private_ike_delete_t *this, message_t *message)
{
delete_payload_t *delete_payload;
delete_payload = delete_payload_create(PROTO_IKE);
message->add_payload(message, (payload_t*)delete_payload);
this->ike_sa->set_state(this->ike_sa, IKE_DELETING);
return NEED_MORE;
}
/**
* Implementation of task_t.process for initiator
*/
static status_t process_i(private_ike_delete_t *this, message_t *message)
{
/* completed, delete IKE_SA by returning FAILED */
return FAILED;
}
/**
* Implementation of task_t.process for initiator
*/
static status_t process_r(private_ike_delete_t *this, message_t *message)
{
/* we don't even scan the payloads, as the message wouldn't have
* come so far without being correct */
switch (this->ike_sa->get_state(this->ike_sa))
{
case IKE_DELETING:
this->simultaneous = TRUE;
break;
case IKE_ESTABLISHED:
DBG1(DBG_IKE, "deleting IKE_SA on request");
/* warn only if we are established */
default:
this->ike_sa->set_state(this->ike_sa, IKE_DELETING);
break;
}
return NEED_MORE;
}
/**
* Implementation of task_t.build for responder
*/
static status_t build_r(private_ike_delete_t *this, message_t *message)
{
if (this->simultaneous)
{
/* wait for peers response for our delete request */
return SUCCESS;
}
/* completed, delete IKE_SA by returning FAILED */
return FAILED;
}
/**
* Implementation of task_t.get_type
*/
static task_type_t get_type(private_ike_delete_t *this)
{
return IKE_DELETE;
}
/**
* Implementation of task_t.migrate
*/
static void migrate(private_ike_delete_t *this, ike_sa_t *ike_sa)
{
this->ike_sa = ike_sa;
this->simultaneous = FALSE;
}
/**
* Implementation of task_t.destroy
*/
static void destroy(private_ike_delete_t *this)
{
free(this);
}
/*
* Described in header.
*/
ike_delete_t *ike_delete_create(ike_sa_t *ike_sa, bool initiator)
{
private_ike_delete_t *this = malloc_thing(private_ike_delete_t);
this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
this->public.task.destroy = (void(*)(task_t*))destroy;
if (initiator)
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
}
else
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
}
this->ike_sa = ike_sa;
this->initiator = initiator;
this->simultaneous = FALSE;
return &this->public;
}
+57
View File
@@ -0,0 +1,57 @@
/**
* @file ike_delete.h
*
* @brief Interface ike_delete_t.
*
*/
/*
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef IKE_DELETE_H_
#define IKE_DELETE_H_
typedef struct ike_delete_t ike_delete_t;
#include <library.h>
#include <sa/ike_sa.h>
#include <sa/tasks/task.h>
/**
* @brief Task of type ike_delete, delete an IKE_SA.
*
* @b Constructors:
* - ike_delete_create()
*
* @ingroup tasks
*/
struct ike_delete_t {
/**
* Implements the task_t interface
*/
task_t task;
};
/**
* @brief Create a new ike_delete task.
*
* @param ike_sa IKE_SA this task works for
* @param initiator TRUE if we initiate the delete
* @return ike_delete task to handle by the task_manager
*/
ike_delete_t *ike_delete_create(ike_sa_t *ike_sa, bool initiator);
#endif /* IKE_DELETE_H_ */
+106
View File
@@ -0,0 +1,106 @@
/**
* @file ike_dpd.c
*
* @brief Implementation of the ike_dpd task.
*
*/
/*
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "ike_dpd.h"
#include <daemon.h>
typedef struct private_ike_dpd_t private_ike_dpd_t;
/**
* Private members of a ike_dpd_t task.
*/
struct private_ike_dpd_t {
/**
* Public methods and task_t interface.
*/
ike_dpd_t public;
};
/**
* Implementation of task_t.build for initiator
* Implementation of task_t.process for responder
*/
static status_t return_need_more(private_ike_dpd_t *this, message_t *message)
{
return NEED_MORE;
}
/**
* Implementation of task_t.process for initiator
* Implementation of task_t.build for responder
*/
static status_t return_success(private_ike_dpd_t *this, message_t *message)
{
return SUCCESS;
}
/**
* Implementation of task_t.get_type
*/
static task_type_t get_type(private_ike_dpd_t *this)
{
return IKE_DEADPEER;
}
/**
* Implementation of task_t.migrate
*/
static void migrate(private_ike_dpd_t *this, ike_sa_t *ike_sa)
{
}
/**
* Implementation of task_t.destroy
*/
static void destroy(private_ike_dpd_t *this)
{
free(this);
}
/*
* Described in header.
*/
ike_dpd_t *ike_dpd_create(bool initiator)
{
private_ike_dpd_t *this = malloc_thing(private_ike_dpd_t);
this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
this->public.task.destroy = (void(*)(task_t*))destroy;
if (initiator)
{
this->public.task.build = (status_t(*)(task_t*,message_t*))return_need_more;
this->public.task.process = (status_t(*)(task_t*,message_t*))return_success;
}
else
{
this->public.task.build = (status_t(*)(task_t*,message_t*))return_success;
this->public.task.process = (status_t(*)(task_t*,message_t*))return_need_more;
}
return &this->public;
}
+58
View File
@@ -0,0 +1,58 @@
/**
* @file ike_dpd.h
*
* @brief Interface ike_dpd_t.
*
*/
/*
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef IKE_DPD_H_
#define IKE_DPD_H_
typedef struct ike_dpd_t ike_dpd_t;
#include <library.h>
#include <sa/ike_sa.h>
#include <sa/tasks/task.h>
/**
* @brief Task of type ike_dpd, detects dead peers.
*
* The DPD task actually does nothing, as a DPD has no associated payloads.
*
* @b Constructors:
* - ike_dpd_create()
*
* @ingroup tasks
*/
struct ike_dpd_t {
/**
* Implements the task_t interface
*/
task_t task;
};
/**
* @brief Create a new ike_dpd task.
*
* @param initiator TRUE if thask is the original initator
* @return ike_dpd task to handle by the task_manager
*/
ike_dpd_t *ike_dpd_create(bool initiator);
#endif /* IKE_DPD_H_ */
+536
View File
@@ -0,0 +1,536 @@
/**
* @file ike_init.c
*
* @brief Implementation of the ike_init task.
*
*/
/*
* Copyright (C) 2005-2007 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "ike_init.h"
#include <string.h>
#include <daemon.h>
#include <crypto/diffie_hellman.h>
#include <encoding/payloads/sa_payload.h>
#include <encoding/payloads/ke_payload.h>
#include <encoding/payloads/nonce_payload.h>
typedef struct private_ike_init_t private_ike_init_t;
/**
* Private members of a ike_init_t task.
*/
struct private_ike_init_t {
/**
* Public methods and task_t interface.
*/
ike_init_t public;
/**
* Assigned IKE_SA.
*/
ike_sa_t *ike_sa;
/**
* Are we the initiator?
*/
bool initiator;
/**
* Connection established by this IKE_SA
*/
connection_t *connection;
/**
* diffie hellman group to use
*/
diffie_hellman_group_t dh_group;
/**
* Diffie hellman object used to generate public DH value.
*/
diffie_hellman_t *diffie_hellman;
/**
* nonce chosen by us
*/
chunk_t my_nonce;
/**
* nonce chosen by peer
*/
chunk_t other_nonce;
/**
* Negotiated proposal used for IKE_SA
*/
proposal_t *proposal;
/**
* Old IKE_SA which gets rekeyed
*/
ike_sa_t *old_sa;
};
/**
* build the payloads for the message
*/
static void build_payloads(private_ike_init_t *this, message_t *message)
{
sa_payload_t *sa_payload;
ke_payload_t *ke_payload;
nonce_payload_t *nonce_payload;
linked_list_t *proposal_list;
ike_sa_id_t *id;
proposal_t *proposal;
iterator_t *iterator;
id = this->ike_sa->get_id(this->ike_sa);
this->connection = this->ike_sa->get_connection(this->ike_sa);
if (this->initiator)
{
proposal_list = this->connection->get_proposals(this->connection);
if (this->old_sa)
{
/* include SPI of new IKE_SA when we are rekeying */
iterator = proposal_list->create_iterator(proposal_list, TRUE);
while (iterator->iterate(iterator, (void**)&proposal))
{
proposal->set_spi(proposal, id->get_initiator_spi(id));
}
iterator->destroy(iterator);
}
sa_payload = sa_payload_create_from_proposal_list(proposal_list);
proposal_list->destroy_offset(proposal_list, offsetof(proposal_t, destroy));
}
else
{
if (this->old_sa)
{
/* include SPI of new IKE_SA when we are rekeying */
this->proposal->set_spi(this->proposal, id->get_responder_spi(id));
}
sa_payload = sa_payload_create_from_proposal(this->proposal);
}
message->add_payload(message, (payload_t*)sa_payload);
ke_payload = ke_payload_create_from_diffie_hellman(this->diffie_hellman);
message->add_payload(message, (payload_t*)ke_payload);
nonce_payload = nonce_payload_create();
nonce_payload->set_nonce(nonce_payload, this->my_nonce);
message->add_payload(message, (payload_t*)nonce_payload);
}
/**
* Read payloads from message
*/
static void process_payloads(private_ike_init_t *this, message_t *message)
{
iterator_t *iterator;
payload_t *payload;
iterator = message->get_payload_iterator(message);
while (iterator->iterate(iterator, (void**)&payload))
{
switch (payload->get_type(payload))
{
case SECURITY_ASSOCIATION:
{
sa_payload_t *sa_payload = (sa_payload_t*)payload;
linked_list_t *proposal_list;
proposal_list = sa_payload->get_proposals(sa_payload);
this->proposal = this->connection->select_proposal(
this->connection, proposal_list);
proposal_list->destroy_offset(proposal_list,
offsetof(proposal_t, destroy));
break;
}
case KEY_EXCHANGE:
{
ke_payload_t *ke_payload = (ke_payload_t*)payload;
diffie_hellman_group_t dh_group;
chunk_t key_data;
dh_group = ke_payload->get_dh_group_number(ke_payload);
if (this->initiator)
{
if (dh_group != this->dh_group)
{
DBG1(DBG_IKE, "received a DH group not requested (%N)",
diffie_hellman_group_names, dh_group);
break;
}
}
else
{
this->dh_group = dh_group;
if (!this->connection->check_dh_group(this->connection,
dh_group))
{
break;
}
this->diffie_hellman = diffie_hellman_create(dh_group);
}
if (this->diffie_hellman)
{
key_data = ke_payload->get_key_exchange_data(ke_payload);
this->diffie_hellman->set_other_public_value(this->diffie_hellman, key_data);
}
break;
}
case NONCE:
{
nonce_payload_t *nonce_payload = (nonce_payload_t*)payload;
this->other_nonce = nonce_payload->get_nonce(nonce_payload);
break;
}
default:
break;
}
}
iterator->destroy(iterator);
}
/**
* Implementation of task_t.process for initiator
*/
static status_t build_i(private_ike_init_t *this, message_t *message)
{
randomizer_t *randomizer;
status_t status;
this->connection = this->ike_sa->get_connection(this->ike_sa);
SIG(IKE_UP_START, "initiating IKE_SA to %H",
this->connection->get_other_host(this->connection));
this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING);
/* if the DH group is set via use_dh_group(), we already have a DH object */
if (!this->diffie_hellman)
{
this->dh_group = this->connection->get_dh_group(this->connection);
this->diffie_hellman = diffie_hellman_create(this->dh_group);
if (this->diffie_hellman == NULL)
{
SIG(IKE_UP_FAILED, "configured DH group %N not supported",
diffie_hellman_group_names, this->dh_group);
return FAILED;
}
}
randomizer = randomizer_create();
status = randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE,
&this->my_nonce);
randomizer->destroy(randomizer);
if (status != SUCCESS)
{
SIG(IKE_UP_FAILED, "error generating random nonce value");
return FAILED;
}
build_payloads(this, message);
return NEED_MORE;
}
/**
* Implementation of task_t.process for initiator
*/
static status_t process_r(private_ike_init_t *this, message_t *message)
{
randomizer_t *randomizer;
this->connection = this->ike_sa->get_connection(this->ike_sa);
SIG(IKE_UP_FAILED, "%H is initiating an IKE_SA",
message->get_source(message));
this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING);
randomizer = randomizer_create();
if (randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE,
&this->my_nonce) != SUCCESS)
{
DBG1(DBG_IKE, "error generating random nonce value");
}
randomizer->destroy(randomizer);
process_payloads(this, message);
return NEED_MORE;
}
/**
* Implementation of task_t.build for responder
*/
static status_t build_r(private_ike_init_t *this, message_t *message)
{
chunk_t secret;
status_t status;
/* check if we have everything we need */
if (this->proposal == NULL ||
this->other_nonce.len == 0 || this->my_nonce.len == 0)
{
SIG(IKE_UP_FAILED, "received proposals inacceptable");
message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty);
return FAILED;
}
if (this->diffie_hellman == NULL ||
this->diffie_hellman->get_shared_secret(this->diffie_hellman,
&secret) != SUCCESS)
{
chunk_t chunk;
u_int16_t dh_enc;
SIG(IKE_UP_FAILED, "received inacceptable DH group (%N)",
diffie_hellman_group_names, this->dh_group);
this->dh_group = this->connection->get_dh_group(this->connection);
dh_enc = htons(this->dh_group);
chunk.ptr = (u_int8_t*)&dh_enc;
chunk.len = sizeof(dh_enc);
message->add_notify(message, TRUE, INVALID_KE_PAYLOAD, chunk);
DBG1(DBG_IKE, "requesting DH group %N",
diffie_hellman_group_names, this->dh_group);
return FAILED;
}
if (this->old_sa)
{
ike_sa_id_t *id;
prf_t *prf, *child_prf;
/* Apply SPI if we are rekeying */
id = this->ike_sa->get_id(this->ike_sa);
id->set_initiator_spi(id, this->proposal->get_spi(this->proposal));
/* setup crypto keys for the rekeyed SA */
prf = this->old_sa->get_prf(this->old_sa);
child_prf = this->old_sa->get_child_prf(this->old_sa);
status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret,
this->other_nonce, this->my_nonce,
FALSE, child_prf, prf);
}
else
{
/* setup crypto keys */
status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret,
this->other_nonce, this->my_nonce,
FALSE, NULL, NULL);
}
if (status != SUCCESS)
{
SIG(IKE_UP_FAILED, "key derivation failed");
message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty);
return FAILED;
}
build_payloads(this, message);
return SUCCESS;
}
/**
* Implementation of task_t.process for initiator
*/
static status_t process_i(private_ike_init_t *this, message_t *message)
{
chunk_t secret;
status_t status;
iterator_t *iterator;
payload_t *payload;
/* check for erronous notifies */
iterator = message->get_payload_iterator(message);
while (iterator->iterate(iterator, (void**)&payload))
{
if (payload->get_type(payload) == NOTIFY)
{
notify_payload_t *notify = (notify_payload_t*)payload;
notify_type_t type = notify->get_notify_type(notify);
switch (type)
{
case INVALID_KE_PAYLOAD:
{
chunk_t data;
diffie_hellman_group_t old_dh_group;
old_dh_group = this->dh_group;
data = notify->get_notification_data(notify);
this->dh_group = ntohs(*((u_int16_t*)data.ptr));
DBG1(DBG_IKE, "peer didn't accept DH group %N, it requested"
" %N", diffie_hellman_group_names, old_dh_group,
diffie_hellman_group_names, this->dh_group);
if (!this->connection->check_dh_group(this->connection,
this->dh_group))
{
SIG(IKE_UP_FAILED, "requested DH group %N not "
"acceptable, giving up", diffie_hellman_group_names,
this->dh_group);
iterator->destroy(iterator);
return FAILED;
}
this->ike_sa->reset(this->ike_sa);
iterator->destroy(iterator);
return NEED_MORE;
}
default:
{
if (type < 16383)
{
SIG(IKE_UP_FAILED, "received %N notify error",
notify_type_names, type);
iterator->destroy(iterator);
return FAILED;
}
}
}
}
}
iterator->destroy(iterator);
process_payloads(this, message);
/* check if we have everything */
if (this->proposal == NULL ||
this->other_nonce.len == 0 || this->my_nonce.len == 0)
{
SIG(IKE_UP_FAILED, "peers proposal selection invalid");
return FAILED;
}
if (this->diffie_hellman == NULL ||
this->diffie_hellman->get_shared_secret(this->diffie_hellman,
&secret) != SUCCESS)
{
SIG(IKE_UP_FAILED, "peers DH group selection invalid");
return FAILED;
}
/* Apply SPI if we are rekeying */
if (this->old_sa)
{
ike_sa_id_t *id;
prf_t *prf, *child_prf;
id = this->ike_sa->get_id(this->ike_sa);
id->set_responder_spi(id, this->proposal->get_spi(this->proposal));
/* setup crypto keys for the rekeyed SA */
prf = this->old_sa->get_prf(this->old_sa);
child_prf = this->old_sa->get_child_prf(this->old_sa);
status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret,
this->my_nonce, this->other_nonce,
TRUE, child_prf, prf);
}
else
{
/* setup crypto keys for a new SA */
status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret,
this->my_nonce, this->other_nonce,
TRUE, NULL, NULL);
}
if (status != SUCCESS)
{
SIG(IKE_UP_FAILED, "key derivation failed");
return FAILED;
}
return SUCCESS;
}
/**
* Implementation of task_t.get_type
*/
static task_type_t get_type(private_ike_init_t *this)
{
return IKE_INIT;
}
/**
* Implementation of task_t.migrate
*/
static void migrate(private_ike_init_t *this, ike_sa_t *ike_sa)
{
DESTROY_IF(this->proposal);
DESTROY_IF(this->diffie_hellman);
chunk_free(&this->my_nonce);
chunk_free(&this->other_nonce);
this->ike_sa = ike_sa;
this->proposal = NULL;
this->diffie_hellman = diffie_hellman_create(this->dh_group);
}
/**
* Implementation of task_t.destroy
*/
static void destroy(private_ike_init_t *this)
{
DESTROY_IF(this->proposal);
DESTROY_IF(this->diffie_hellman);
chunk_free(&this->my_nonce);
chunk_free(&this->other_nonce);
free(this);
}
/*
* Described in header.
*/
ike_init_t *ike_init_create(ike_sa_t *ike_sa, bool initiator, ike_sa_t *old_sa)
{
private_ike_init_t *this = malloc_thing(private_ike_init_t);
this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
this->public.task.destroy = (void(*)(task_t*))destroy;
if (initiator)
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
}
else
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
}
this->ike_sa = ike_sa;
this->initiator = initiator;
this->dh_group = MODP_NONE;
this->diffie_hellman = NULL;
this->my_nonce = chunk_empty;
this->other_nonce = chunk_empty;
this->proposal = NULL;
this->connection = NULL;
this->old_sa = old_sa;
return &this->public;
}
+60
View File
@@ -0,0 +1,60 @@
/**
* @file ike_init.h
*
* @brief Interface ike_init_t.
*
*/
/*
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef IKE_INIT_H_
#define IKE_INIT_H_
typedef struct ike_init_t ike_init_t;
#include <library.h>
#include <sa/ike_sa.h>
#include <sa/tasks/task.h>
/**
* @brief Task of type IKE_INIT, creates an IKE_SA without authentication.
*
* The authentication of is handle in the ike_auth and/or ike_auth_eap task.
*
* @b Constructors:
* - ike_init_create()
*
* @ingroup tasks
*/
struct ike_init_t {
/**
* Implements the task_t interface
*/
task_t task;
};
/**
* @brief Create a new IKE_INIT task.
*
* @param ike_sa IKE_SA this task works for (new one when rekeying)
* @param initiator TRUE if thask is the original initator
* @param old_sa old IKE_SA when we are rekeying
* @return ike_init task to handle by the task_manager
*/
ike_init_t *ike_init_create(ike_sa_t *ike_sa, bool initiator, ike_sa_t *old_sa);
#endif /* IKE_INIT_H_ */
+378
View File
@@ -0,0 +1,378 @@
/**
* @file ike_natd.c
*
* @brief Implementation of the ike_natd task.
*
*/
/*
* Copyright (C) 2006-2007 Martin Willi
* Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "ike_natd.h"
#include <string.h>
#include <daemon.h>
#include <crypto/hashers/hasher.h>
#include <encoding/payloads/notify_payload.h>
typedef struct private_ike_natd_t private_ike_natd_t;
/**
* Private members of a ike_natd_t task.
*/
struct private_ike_natd_t {
/**
* Public methods and task_t interface.
*/
ike_natd_t public;
/**
* Assigned IKE_SA.
*/
ike_sa_t *ike_sa;
/**
* Are we the initiator?
*/
bool initiator;
/**
* Hasher used to build NAT detection hashes
*/
hasher_t *hasher;
/**
* Did we process any NAT detection notifys for a source address?
*/
bool src_seen;
/**
* Did we process any NAT detection notifys for a destination address?
*/
bool dst_seen;
/**
* Have we found a matching source address NAT hash?
*/
bool src_matched;
/**
* Have we found a matching destination address NAT hash?
*/
bool dst_matched;
};
/**
* Build NAT detection hash for a host
*/
static chunk_t generate_natd_hash(private_ike_natd_t *this,
ike_sa_id_t *ike_sa_id, host_t *host)
{
chunk_t natd_chunk, spi_i_chunk, spi_r_chunk, addr_chunk, port_chunk;
chunk_t natd_hash;
u_int64_t spi_i, spi_r;
u_int16_t port;
/* prepare all requred chunks */
spi_i = ike_sa_id->get_initiator_spi(ike_sa_id);
spi_r = ike_sa_id->get_responder_spi(ike_sa_id);
spi_i_chunk.ptr = (void*)&spi_i;
spi_i_chunk.len = sizeof(spi_i);
spi_r_chunk.ptr = (void*)&spi_r;
spi_r_chunk.len = sizeof(spi_r);
port = htons(host->get_port(host));
port_chunk.ptr = (void*)&port;
port_chunk.len = sizeof(port);
addr_chunk = host->get_address(host);
DBG2(DBG_IKE, "using SPI %J", ike_sa_id);
/* natd_hash = SHA1( spi_i | spi_r | address | port ) */
natd_chunk = chunk_cat("cccc", spi_i_chunk, spi_r_chunk, addr_chunk, port_chunk);
this->hasher->allocate_hash(this->hasher, natd_chunk, &natd_hash);
DBG3(DBG_IKE, "natd_chunk %B", &natd_chunk);
DBG3(DBG_IKE, "natd_hash %B", &natd_hash);
chunk_free(&natd_chunk);
return natd_hash;
}
/**
* Build a NAT detection notify payload.
*/
static notify_payload_t *build_natd_payload(private_ike_natd_t *this,
notify_type_t type, host_t *host)
{
chunk_t hash;
notify_payload_t *notify;
ike_sa_id_t *ike_sa_id;
ike_sa_id = this->ike_sa->get_id(this->ike_sa);
notify = notify_payload_create();
notify->set_notify_type(notify, type);
hash = generate_natd_hash(this, ike_sa_id, host);
notify->set_notification_data(notify, hash);
chunk_free(&hash);
return notify;
}
/**
* read notifys from message and evaluate them
*/
static void process_payloads(private_ike_natd_t *this, message_t *message)
{
iterator_t *iterator;
payload_t *payload;
notify_payload_t *notify;
chunk_t hash, src_hash, dst_hash;
ike_sa_id_t *ike_sa_id;
host_t *me, *other;
/* Precompute NAT-D hashes for incoming NAT notify comparison */
ike_sa_id = message->get_ike_sa_id(message);
me = this->ike_sa->get_my_host(this->ike_sa);
other = this->ike_sa->get_other_host(this->ike_sa);
dst_hash = generate_natd_hash(this, ike_sa_id, me);
src_hash = generate_natd_hash(this, ike_sa_id, other);
DBG2(DBG_IKE, "precalculated src_hash %B", &src_hash);
DBG2(DBG_IKE, "precalculated dst_hash %B", &dst_hash);
iterator = message->get_payload_iterator(message);
while (iterator->iterate(iterator, (void**)&payload))
{
if (payload->get_type(payload) != NOTIFY)
{
continue;
}
notify = (notify_payload_t*)payload;
switch (notify->get_notify_type(notify))
{
case NAT_DETECTION_DESTINATION_IP:
{
this->dst_seen = TRUE;
if (!this->dst_matched)
{
hash = notify->get_notification_data(notify);
DBG2(DBG_IKE, "received dst_hash %B", &hash);
if (chunk_equals(hash, dst_hash))
{
this->dst_matched = TRUE;
}
}
break;
}
case NAT_DETECTION_SOURCE_IP:
{
this->src_seen = TRUE;
if (!this->src_matched)
{
hash = notify->get_notification_data(notify);
DBG2(DBG_IKE, "received src_hash %B", &hash);
if (chunk_equals(hash, src_hash))
{
this->src_matched = TRUE;
}
}
break;
}
default:
break;
}
}
iterator->destroy(iterator);
chunk_free(&src_hash);
chunk_free(&dst_hash);
if (this->src_seen && this->dst_seen)
{
if (!this->dst_matched)
{
this->ike_sa->enable_natt(this->ike_sa, TRUE);
}
if (!this->src_matched)
{
this->ike_sa->enable_natt(this->ike_sa, FALSE);
}
}
}
/**
* Implementation of task_t.process for initiator
*/
static status_t process_i(private_ike_natd_t *this, message_t *message)
{
process_payloads(this, message);
if (this->ike_sa->is_natt_enabled(this->ike_sa))
{
host_t *me, *other;
me = this->ike_sa->get_my_host(this->ike_sa);
me->set_port(me, IKEV2_NATT_PORT);
other = this->ike_sa->get_other_host(this->ike_sa);
other->set_port(other, IKEV2_NATT_PORT);
}
return SUCCESS;
}
/**
* Implementation of task_t.process for initiator
*/
static status_t build_i(private_ike_natd_t *this, message_t *message)
{
notify_payload_t *notify;
linked_list_t *list;
host_t *host;
/* include one notify if our address is defined, all addresses otherwise */
host = this->ike_sa->get_my_host(this->ike_sa);
if (host->is_anyaddr(host))
{
/* TODO: we could get the src address from netlink!? */
list = charon->socket->create_local_address_list(charon->socket);
while (list->remove_first(list, (void**)&host) == SUCCESS)
{
notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host);
host->destroy(host);
message->add_payload(message, (payload_t*)notify);
}
list->destroy(list);
}
else
{
notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host);
message->add_payload(message, (payload_t*)notify);
}
host = this->ike_sa->get_other_host(this->ike_sa);
notify = build_natd_payload(this, NAT_DETECTION_DESTINATION_IP, host);
message->add_payload(message, (payload_t*)notify);
return NEED_MORE;
}
/**
* Implementation of task_t.build for responder
*/
static status_t build_r(private_ike_natd_t *this, message_t *message)
{
notify_payload_t *notify;
host_t *me, *other;
iterator_t *iterator;
u_int count;
/* when only one payload is in the message, an error occured.
* TODO: find a better hack */
iterator = message->get_payload_iterator(message);
count = iterator->get_count(iterator);
iterator->destroy(iterator);
if (count < 3)
{
return NEED_MORE;
}
if (this->src_seen && this->dst_seen)
{
/* initiator seems to support NAT detection, add response */
me = this->ike_sa->get_my_host(this->ike_sa);
notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, me);
message->add_payload(message, (payload_t*)notify);
other = this->ike_sa->get_other_host(this->ike_sa);
notify = build_natd_payload(this, NAT_DETECTION_DESTINATION_IP, other);
message->add_payload(message, (payload_t*)notify);
}
return SUCCESS;
}
/**
* Implementation of task_t.process for responder
*/
static status_t process_r(private_ike_natd_t *this, message_t *message)
{
process_payloads(this, message);
return NEED_MORE;
}
/**
* Implementation of task_t.get_type
*/
static task_type_t get_type(private_ike_natd_t *this)
{
return IKE_NATD;
}
/**
* Implementation of task_t.migrate
*/
static void migrate(private_ike_natd_t *this, ike_sa_t *ike_sa)
{
this->ike_sa = ike_sa;
this->src_seen = FALSE;
this->dst_seen = FALSE;
this->src_matched = FALSE;
this->dst_matched = FALSE;
}
/**
* Implementation of task_t.destroy
*/
static void destroy(private_ike_natd_t *this)
{
this->hasher->destroy(this->hasher);
free(this);
}
/*
* Described in header.
*/
ike_natd_t *ike_natd_create(ike_sa_t *ike_sa, bool initiator)
{
private_ike_natd_t *this = malloc_thing(private_ike_natd_t);
this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
this->public.task.destroy = (void(*)(task_t*))destroy;
if (initiator)
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
}
else
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
}
this->ike_sa = ike_sa;
this->initiator = initiator;
this->hasher = hasher_create(HASH_SHA1);
this->src_seen = FALSE;
this->dst_seen = FALSE;
this->src_matched = FALSE;
this->dst_matched = FALSE;
return &this->public;
}
+57
View File
@@ -0,0 +1,57 @@
/**
* @file ike_natd.h
*
* @brief Interface ike_natd_t.
*
*/
/*
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef IKE_NATD_H_
#define IKE_NATD_H_
typedef struct ike_natd_t ike_natd_t;
#include <library.h>
#include <sa/ike_sa.h>
#include <sa/tasks/task.h>
/**
* @brief Task of type ike_natd, detects NAT situation in IKE_SA_INIT exchange.
*
* @b Constructors:
* - ike_natd_create()
*
* @ingroup tasks
*/
struct ike_natd_t {
/**
* Implements the task_t interface
*/
task_t task;
};
/**
* @brief Create a new ike_natd task.
*
* @param ike_sa IKE_SA this task works for
* @param initiator TRUE if thask is the original initator
* @return ike_natd task to handle by the task_manager
*/
ike_natd_t *ike_natd_create(ike_sa_t *ike_sa, bool initiator);
#endif /* IKE_NATD_H_ */
+232
View File
@@ -0,0 +1,232 @@
/**
* @file ike_rekey.c
*
* @brief Implementation of the ike_rekey task.
*
*/
/*
* Copyright (C) 2005-2007 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "ike_rekey.h"
#include <daemon.h>
#include <crypto/diffie_hellman.h>
#include <encoding/payloads/notify_payload.h>
#include <encoding/payloads/nonce_payload.h>
#include <sa/tasks/ike_init.h>
#include <queues/jobs/delete_ike_sa_job.h>
typedef struct private_ike_rekey_t private_ike_rekey_t;
/**
* Private members of a ike_rekey_t task.
*/
struct private_ike_rekey_t {
/**
* Public methods and task_t interface.
*/
ike_rekey_t public;
/**
* Assigned IKE_SA.
*/
ike_sa_t *ike_sa;
/**
* New IKE_SA which replaces the current one
*/
ike_sa_t *new_sa;
/**
* Are we the initiator?
*/
bool initiator;
/**
* the IKE_INIT task which is reused to simplify rekeying
*/
ike_init_t *ike_init;
};
/**
* Implementation of task_t.build for initiator
*/
static status_t build_i(private_ike_rekey_t *this, message_t *message)
{
connection_t *connection;
policy_t *policy;
ike_sa_id_t *id;
id = ike_sa_id_create(0, 0, TRUE);
this->new_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, id);
id->destroy(id);
connection = this->ike_sa->get_connection(this->ike_sa);
policy = this->ike_sa->get_policy(this->ike_sa);
this->new_sa->set_connection(this->new_sa, connection);
this->new_sa->set_policy(this->new_sa, policy);
this->ike_init = ike_init_create(this->new_sa, TRUE, this->ike_sa);
this->ike_init->task.build(&this->ike_init->task, message);
this->ike_sa->set_state(this->ike_sa, IKE_REKEYING);
return NEED_MORE;
}
/**
* Implementation of task_t.process for initiator
*/
static status_t process_r(private_ike_rekey_t *this, message_t *message)
{
connection_t *connection;
policy_t *policy;
ike_sa_id_t *id;
id = ike_sa_id_create(0, 0, FALSE);
this->new_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, id);
id->destroy(id);
connection = this->ike_sa->get_connection(this->ike_sa);
policy = this->ike_sa->get_policy(this->ike_sa);
this->new_sa->set_connection(this->new_sa, connection);
this->new_sa->set_policy(this->new_sa, policy);
this->ike_init = ike_init_create(this->new_sa, FALSE, this->ike_sa);
this->ike_init->task.process(&this->ike_init->task, message);
return NEED_MORE;
}
/**
* Implementation of task_t.build for responder
*/
static status_t build_r(private_ike_rekey_t *this, message_t *message)
{
if (this->ike_init->task.build(&this->ike_init->task, message) == FAILED)
{
return SUCCESS;
}
this->ike_sa->set_state(this->ike_sa, IKE_REKEYING);
this->new_sa->inherit(this->new_sa, this->ike_sa);
this->new_sa->set_state(this->new_sa, IKE_ESTABLISHED);
charon->ike_sa_manager->checkin(charon->ike_sa_manager, this->new_sa);
this->new_sa = NULL;
return SUCCESS;
}
/**
* Implementation of task_t.process for initiator
*/
static status_t process_i(private_ike_rekey_t *this, message_t *message)
{
job_t *job;
if (this->ike_init->task.process(&this->ike_init->task, message) == FAILED)
{
return SUCCESS;
}
this->new_sa->set_state(this->new_sa, IKE_ESTABLISHED);
this->new_sa->inherit(this->new_sa, this->ike_sa);
charon->ike_sa_manager->checkin(charon->ike_sa_manager, this->new_sa);
this->new_sa = NULL;
job = (job_t*)delete_ike_sa_job_create(this->ike_sa->get_id(this->ike_sa),
TRUE);
charon->job_queue->add(charon->job_queue, job);
return SUCCESS;
}
/**
* Implementation of task_t.get_type
*/
static task_type_t get_type(private_ike_rekey_t *this)
{
return IKE_REKEY;
}
/**
* Implementation of task_t.migrate
*/
static void migrate(private_ike_rekey_t *this, ike_sa_t *ike_sa)
{
if (this->ike_init)
{
this->ike_init->task.destroy(&this->ike_init->task);
}
if (this->new_sa)
{
charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
this->new_sa);
}
this->ike_sa = ike_sa;
this->new_sa = NULL;
this->ike_init = NULL;
}
/**
* Implementation of task_t.destroy
*/
static void destroy(private_ike_rekey_t *this)
{
if (this->ike_init)
{
this->ike_init->task.destroy(&this->ike_init->task);
}
if (this->new_sa)
{
charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
this->new_sa);
}
free(this);
}
/*
* Described in header.
*/
ike_rekey_t *ike_rekey_create(ike_sa_t *ike_sa, bool initiator)
{
private_ike_rekey_t *this = malloc_thing(private_ike_rekey_t);
this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
this->public.task.destroy = (void(*)(task_t*))destroy;
if (initiator)
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
}
else
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
}
this->ike_sa = ike_sa;
this->new_sa = NULL;
this->ike_init = NULL;
this->initiator = initiator;
return &this->public;
}
+57
View File
@@ -0,0 +1,57 @@
/**
* @file ike_rekey.h
*
* @brief Interface ike_rekey_t.
*
*/
/*
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef IKE_REKEY_H_
#define IKE_REKEY_H_
typedef struct ike_rekey_t ike_rekey_t;
#include <library.h>
#include <sa/ike_sa.h>
#include <sa/tasks/task.h>
/**
* @brief Task of type IKE_REKEY, rekey an established IKE_SA.
*
* @b Constructors:
* - ike_rekey_create()
*
* @ingroup tasks
*/
struct ike_rekey_t {
/**
* Implements the task_t interface
*/
task_t task;
};
/**
* @brief Create a new IKE_REKEY task.
*
* @param ike_sa IKE_SA this task works for
* @param initiator TRUE for initiator, FALSE for responder
* @return IKE_REKEY task to handle by the task_manager
*/
ike_rekey_t *ike_rekey_create(ike_sa_t *ike_sa, bool initiator);
#endif /* IKE_REKEY_H_ */
+38
View File
@@ -0,0 +1,38 @@
/**
* @file task.c
*
* @brief Enum values for task types
*
*/
/*
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "task.h"
ENUM(task_type_names, IKE_INIT, CHILD_REKEY,
"IKE_INIT",
"IKE_NATD",
"IKE_AUTHENTICATE",
"IKE_CERT",
"IKE_CONFIG",
"IKE_DPD",
"IKE_REKEY",
"IKE_DELETE",
"IKE_DEADPEER",
"CHILD_CREATE",
"CHILD_DELETE",
"CHILD_REKEY",
);
+151
View File
@@ -0,0 +1,151 @@
/**
* @file task.h
*
* @brief Interface task_t.
*
*/
/*
* Copyright (C) 2006 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef TASK_H_
#define TASK_H_
typedef enum task_type_t task_type_t;
typedef struct task_t task_t;
#include <library.h>
#include <sa/ike_sa.h>
#include <encoding/message.h>
/**
* @brief Different kinds of tasks.
*
* @ingroup tasks
*/
enum task_type_t {
/** establish an unauthenticated IKE_SA */
IKE_INIT,
/** detect NAT situation */
IKE_NATD,
/** authenticate the initiated IKE_SA */
IKE_AUTHENTICATE,
/** exchange certificates and requests */
IKE_CERT,
/** Configuration payloads, virtual IP and such */
IKE_CONFIG,
/** DPD detection */
IKE_DEADPEER,
/** rekey an IKE_SA */
IKE_REKEY,
/** delete an IKE_SA */
IKE_DELETE,
/** liveness check */
IKE_DPD,
/** establish a CHILD_SA within an IKE_SA */
CHILD_CREATE,
/** delete an established CHILD_SA */
CHILD_DELETE,
/** rekey an CHILD_SA */
CHILD_REKEY,
};
/**
* enum names for task_type_t.
*/
extern enum_name_t *task_type_names;
/**
* @brief Interface for a task, an operation handled within exchanges.
*
* A task is an elemantary operation. It may be handled by a single or by
* multiple exchanges. An exchange may even complete multiple tasks.
* A task has a build() and an process() operation. The build() operation
* creates payloads and adds it to the message. The process() operation
* inspects a message and handles its payloads. An initiator of an exchange
* first calls build() to build the request, and processes the response message
* with the process() method.
* A responder does the opposite; it calls process() first to handle an incoming
* request and secondly calls build() to build an appropriate response.
* Both methods return either SUCCESS, NEED_MORE or FAILED. A SUCCESS indicates
* that the task completed, even when the task completed unsuccesfully. The
* manager then removes the task from the list. A NEED_MORE is returned when
* the task needs further build()/process() calls to complete, the manager
* leaves the taks in the queue. A returned FAILED indicates a critical failure.
* The manager closes the IKE_SA whenever a task returns FAILED.
*
* @b Constructors:
* - None, use implementations specific constructors
*
* @ingroup tasks
*/
struct task_t {
/**
* @brief Build a request or response message for this task.
*
* @param this calling object
* @param message message to add payloads to
* @return
* - FAILED if a critical error occured
* - NEED_MORE if another call to build/process needed
* - SUCCESS if task completed
*/
status_t (*build) (task_t *this, message_t *message);
/**
* @brief Process a request or response message for this task.
*
* @param this calling object
* @param message message to read payloads from
* @return
* - FAILED if a critical error occured
* - NEED_MORE if another call to build/process needed
* - SUCCESS if task completed
*/
status_t (*process) (task_t *this, message_t *message);
/**
* @brief Get the type of the task implementation.
*
* @param this calling object
*/
task_type_t (*get_type) (task_t *this);
/**
* @brief Migrate a task to a new IKE_SA.
*
* After migrating a task, it goes back to a state where it can be
* used again to initate an exchange. This is useful when a task
* has to get migrated to a new IKE_SA.
* A special usage is when a INVALID_KE_PAYLOAD is received. A call
* to reset resets the task, but uses another DH group for the next
* try.
* The ike_sa is the new IKE_SA this task belongs to and operates on.
*
* @param this calling object
* @param ike_sa new IKE_SA this task works for
*/
void (*migrate) (task_t *this, ike_sa_t *ike_sa);
/**
* @brief Destroys a task_t object.
*
* @param this calling object
*/
void (*destroy) (task_t *this);
};
#endif /* TASK_H_ */