Install negotiated IKEv1 CHILD_SA negotiated in quick mode

This commit is contained in:
Martin Willi
2012-03-20 17:30:48 +01:00
parent ff2a2ad33a
commit 5351d63c79
+163
View File
@@ -18,6 +18,7 @@
#include <string.h>
#include <daemon.h>
#include <sa/keymat_v1.h>
#include <encoding/payloads/sa_payload.h>
#include <encoding/payloads/nonce_payload.h>
#include <encoding/payloads/id_payload.h>
@@ -39,6 +40,11 @@ struct private_quick_mode_t {
*/
ike_sa_t *ike_sa;
/**
* TRUE if we are initiating quick mode
*/
bool initiator;
/**
* Traffic selector of initiator
*/
@@ -59,6 +65,16 @@ struct private_quick_mode_t {
*/
chunk_t nonce_r;
/**
* Initiators ESP SPI
*/
u_int32_t spi_i;
/**
* Responder ESP SPI
*/
u_int32_t spi_r;
/**
* selected CHILD_SA proposal
*/
@@ -74,6 +90,11 @@ struct private_quick_mode_t {
*/
child_sa_t *child_sa;
/**
* IKEv1 keymat
*/
keymat_v1_t *keymat;
/** states of quick mode */
enum {
QM_INIT,
@@ -81,6 +102,100 @@ struct private_quick_mode_t {
} state;
};
/**
* Install negotiated CHILD_SA
*/
static bool install(private_quick_mode_t *this)
{
status_t status, status_i, status_o;
chunk_t encr_i, encr_r, integ_i, integ_r;
linked_list_t *tsi, *tsr;
this->child_sa->set_proposal(this->child_sa, this->proposal);
this->child_sa->set_state(this->child_sa, CHILD_INSTALLING);
this->child_sa->set_mode(this->child_sa, MODE_TUNNEL);
this->child_sa->set_protocol(this->child_sa,
this->proposal->get_protocol(this->proposal));
status_i = status_o = FAILED;
encr_i = encr_r = integ_i = integ_r = chunk_empty;
tsi = linked_list_create();
tsr = linked_list_create();
tsi->insert_last(tsi, this->tsi);
tsr->insert_last(tsr, this->tsr);
if (this->keymat->derive_child_keys(this->keymat, this->proposal, NULL,
this->nonce_i, this->nonce_r, &encr_i, &integ_i, &encr_r, &integ_r))
{
if (this->initiator)
{
status_i = this->child_sa->install(this->child_sa, encr_r, integ_r,
this->spi_i, 0, TRUE, FALSE, tsi, tsr);
status_o = this->child_sa->install(this->child_sa, encr_i, integ_i,
this->spi_r, 0, FALSE, FALSE, tsi, tsr);
}
else
{
status_i = this->child_sa->install(this->child_sa, encr_i, integ_i,
this->spi_r, 0, TRUE, FALSE, tsr, tsi);
status_o = this->child_sa->install(this->child_sa, encr_r, integ_r,
this->spi_i, 0, FALSE, FALSE, tsr, tsi);
}
}
chunk_clear(&integ_i);
chunk_clear(&integ_r);
chunk_clear(&encr_i);
chunk_clear(&encr_r);
if (status_i != SUCCESS || status_o != SUCCESS)
{
DBG1(DBG_IKE, "unable to install %s%s%sIPsec SA (SAD) in kernel",
(status_i != SUCCESS) ? "inbound " : "",
(status_i != SUCCESS && status_o != SUCCESS) ? "and ": "",
(status_o != SUCCESS) ? "outbound " : "");
tsi->destroy(tsi);
tsr->destroy(tsr);
return FALSE;
}
if (this->initiator)
{
status = this->child_sa->add_policies(this->child_sa, tsi, tsr);
}
else
{
status = this->child_sa->add_policies(this->child_sa, tsr, tsi);
}
tsi->destroy(tsi);
tsr->destroy(tsr);
if (status != SUCCESS)
{
DBG1(DBG_IKE, "unable to install IPsec policies (SPD) in kernel");
return FALSE;
}
charon->bus->child_keys(charon->bus, this->child_sa, this->initiator,
NULL, this->nonce_i, this->nonce_r);
/* 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);
DBG0(DBG_IKE, "CHILD_SA %s{%d} established "
"with SPIs %.8x_i %.8x_o and TS %#R=== %#R",
this->child_sa->get_name(this->child_sa),
this->child_sa->get_reqid(this->child_sa),
ntohl(this->child_sa->get_spi(this->child_sa, TRUE)),
ntohl(this->child_sa->get_spi(this->child_sa, FALSE)),
this->child_sa->get_traffic_selectors(this->child_sa, TRUE),
this->child_sa->get_traffic_selectors(this->child_sa, FALSE));
charon->bus->child_updown(charon->bus, this->child_sa, TRUE);
this->child_sa = NULL;
return TRUE;
}
METHOD(task_t, build_i, status_t,
private_quick_mode_t *this, message_t *message)
{
@@ -88,14 +203,35 @@ METHOD(task_t, build_i, status_t,
{
case QM_INIT:
{
enumerator_t *enumerator;
sa_payload_t *sa_payload;
nonce_payload_t *nonce_payload;
id_payload_t *id_payload;
traffic_selector_t *ts;
linked_list_t *list;
proposal_t *proposal;
rng_t *rng;
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->config, 0, FALSE);
list = this->config->get_proposals(this->config, TRUE);
this->spi_i = this->child_sa->alloc_spi(this->child_sa, PROTO_ESP);
if (!this->spi_i)
{
DBG1(DBG_IKE, "allocating SPI from kernel failed");
return FAILED;
}
enumerator = list->create_enumerator(list);
while (enumerator->enumerate(enumerator, &proposal))
{
proposal->set_spi(proposal, this->spi_i);
}
enumerator->destroy(enumerator);
sa_payload = sa_payload_create_from_proposal_list(
SECURITY_ASSOCIATION_V1, list);
list->destroy_offset(list, offsetof(proposal_t, destroy));
@@ -234,6 +370,7 @@ METHOD(task_t, process_r, status_t,
DBG1(DBG_IKE, "no matching proposal found");
return FAILED;
}
this->spi_i = this->proposal->get_spi(this->proposal);
nonce_payload = (nonce_payload_t*)message->get_payload(message,
NONCE_V1);
@@ -246,12 +383,21 @@ METHOD(task_t, process_r, status_t,
/* TODO-IKEv1: verify HASH(1) */
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->config, 0, FALSE);
return NEED_MORE;
}
case QM_NEGOTIATED:
{
/* TODO-IKEv1: verify HASH(3) */
if (!install(this))
{
return FAILED;
}
return SUCCESS;
}
default:
@@ -271,6 +417,14 @@ METHOD(task_t, build_r, status_t,
id_payload_t *id_payload;
rng_t *rng;
this->spi_r = this->child_sa->alloc_spi(this->child_sa, PROTO_ESP);
if (!this->spi_r)
{
DBG1(DBG_IKE, "allocating SPI from kernel failed");
return FAILED;
}
this->proposal->set_spi(this->proposal, this->spi_r);
sa_payload = sa_payload_create_from_proposal(
SECURITY_ASSOCIATION_V1, this->proposal);
message->add_payload(message, &sa_payload->payload_interface);
@@ -370,6 +524,8 @@ METHOD(task_t, process_i, status_t,
DBG1(DBG_IKE, "no matching proposal found");
return FAILED;
}
this->spi_r = this->proposal->get_spi(this->proposal);
nonce_payload = (nonce_payload_t*)message->get_payload(message,
NONCE_V1);
if (!nonce_payload)
@@ -381,6 +537,11 @@ METHOD(task_t, process_i, status_t,
/* TODO-IKEv1: verify HASH(2) */
if (!install(this))
{
return FAILED;
}
this->state = QM_NEGOTIATED;
return NEED_MORE;
}
@@ -431,7 +592,9 @@ quick_mode_t *quick_mode_create(ike_sa_t *ike_sa, child_cfg_t *config,
},
},
.ike_sa = ike_sa,
.initiator = config != NULL,
.config = config,
.keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa),
.state = QM_INIT,
);