Install negotiated IKEv1 CHILD_SA negotiated in quick mode
This commit is contained in:
@@ -18,6 +18,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <daemon.h>
|
#include <daemon.h>
|
||||||
|
#include <sa/keymat_v1.h>
|
||||||
#include <encoding/payloads/sa_payload.h>
|
#include <encoding/payloads/sa_payload.h>
|
||||||
#include <encoding/payloads/nonce_payload.h>
|
#include <encoding/payloads/nonce_payload.h>
|
||||||
#include <encoding/payloads/id_payload.h>
|
#include <encoding/payloads/id_payload.h>
|
||||||
@@ -39,6 +40,11 @@ struct private_quick_mode_t {
|
|||||||
*/
|
*/
|
||||||
ike_sa_t *ike_sa;
|
ike_sa_t *ike_sa;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TRUE if we are initiating quick mode
|
||||||
|
*/
|
||||||
|
bool initiator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Traffic selector of initiator
|
* Traffic selector of initiator
|
||||||
*/
|
*/
|
||||||
@@ -59,6 +65,16 @@ struct private_quick_mode_t {
|
|||||||
*/
|
*/
|
||||||
chunk_t nonce_r;
|
chunk_t nonce_r;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initiators ESP SPI
|
||||||
|
*/
|
||||||
|
u_int32_t spi_i;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Responder ESP SPI
|
||||||
|
*/
|
||||||
|
u_int32_t spi_r;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* selected CHILD_SA proposal
|
* selected CHILD_SA proposal
|
||||||
*/
|
*/
|
||||||
@@ -74,6 +90,11 @@ struct private_quick_mode_t {
|
|||||||
*/
|
*/
|
||||||
child_sa_t *child_sa;
|
child_sa_t *child_sa;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IKEv1 keymat
|
||||||
|
*/
|
||||||
|
keymat_v1_t *keymat;
|
||||||
|
|
||||||
/** states of quick mode */
|
/** states of quick mode */
|
||||||
enum {
|
enum {
|
||||||
QM_INIT,
|
QM_INIT,
|
||||||
@@ -81,6 +102,100 @@ struct private_quick_mode_t {
|
|||||||
} state;
|
} 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,
|
METHOD(task_t, build_i, status_t,
|
||||||
private_quick_mode_t *this, message_t *message)
|
private_quick_mode_t *this, message_t *message)
|
||||||
{
|
{
|
||||||
@@ -88,14 +203,35 @@ METHOD(task_t, build_i, status_t,
|
|||||||
{
|
{
|
||||||
case QM_INIT:
|
case QM_INIT:
|
||||||
{
|
{
|
||||||
|
enumerator_t *enumerator;
|
||||||
sa_payload_t *sa_payload;
|
sa_payload_t *sa_payload;
|
||||||
nonce_payload_t *nonce_payload;
|
nonce_payload_t *nonce_payload;
|
||||||
id_payload_t *id_payload;
|
id_payload_t *id_payload;
|
||||||
traffic_selector_t *ts;
|
traffic_selector_t *ts;
|
||||||
linked_list_t *list;
|
linked_list_t *list;
|
||||||
|
proposal_t *proposal;
|
||||||
rng_t *rng;
|
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);
|
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(
|
sa_payload = sa_payload_create_from_proposal_list(
|
||||||
SECURITY_ASSOCIATION_V1, list);
|
SECURITY_ASSOCIATION_V1, list);
|
||||||
list->destroy_offset(list, offsetof(proposal_t, destroy));
|
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");
|
DBG1(DBG_IKE, "no matching proposal found");
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
|
this->spi_i = this->proposal->get_spi(this->proposal);
|
||||||
|
|
||||||
nonce_payload = (nonce_payload_t*)message->get_payload(message,
|
nonce_payload = (nonce_payload_t*)message->get_payload(message,
|
||||||
NONCE_V1);
|
NONCE_V1);
|
||||||
@@ -246,12 +383,21 @@ METHOD(task_t, process_r, status_t,
|
|||||||
|
|
||||||
/* TODO-IKEv1: verify HASH(1) */
|
/* 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;
|
return NEED_MORE;
|
||||||
}
|
}
|
||||||
case QM_NEGOTIATED:
|
case QM_NEGOTIATED:
|
||||||
{
|
{
|
||||||
/* TODO-IKEv1: verify HASH(3) */
|
/* TODO-IKEv1: verify HASH(3) */
|
||||||
|
|
||||||
|
if (!install(this))
|
||||||
|
{
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -271,6 +417,14 @@ METHOD(task_t, build_r, status_t,
|
|||||||
id_payload_t *id_payload;
|
id_payload_t *id_payload;
|
||||||
rng_t *rng;
|
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(
|
sa_payload = sa_payload_create_from_proposal(
|
||||||
SECURITY_ASSOCIATION_V1, this->proposal);
|
SECURITY_ASSOCIATION_V1, this->proposal);
|
||||||
message->add_payload(message, &sa_payload->payload_interface);
|
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");
|
DBG1(DBG_IKE, "no matching proposal found");
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
|
this->spi_r = this->proposal->get_spi(this->proposal);
|
||||||
|
|
||||||
nonce_payload = (nonce_payload_t*)message->get_payload(message,
|
nonce_payload = (nonce_payload_t*)message->get_payload(message,
|
||||||
NONCE_V1);
|
NONCE_V1);
|
||||||
if (!nonce_payload)
|
if (!nonce_payload)
|
||||||
@@ -381,6 +537,11 @@ METHOD(task_t, process_i, status_t,
|
|||||||
|
|
||||||
/* TODO-IKEv1: verify HASH(2) */
|
/* TODO-IKEv1: verify HASH(2) */
|
||||||
|
|
||||||
|
if (!install(this))
|
||||||
|
{
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
this->state = QM_NEGOTIATED;
|
this->state = QM_NEGOTIATED;
|
||||||
return NEED_MORE;
|
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,
|
.ike_sa = ike_sa,
|
||||||
|
.initiator = config != NULL,
|
||||||
.config = config,
|
.config = config,
|
||||||
|
.keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa),
|
||||||
.state = QM_INIT,
|
.state = QM_INIT,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user