child-create: Add support for multiple key exchanges

It also changes that payloads are built before installing the CHILD_SA on
the responder, that is, the KE payload is generated before keys are derived,
so that key_exchange_t::get_public_key() is called before get_shared_secret(),
or it's internal equivalent, which could be relevant for KE implementations
that want to ensure that the key can't be used again after the key
derivation.
This commit is contained in:
Tobias Brunner 2020-06-25 10:26:38 +02:00
parent d3da7b1fdd
commit abce9feb6a
5 changed files with 740 additions and 225 deletions

View File

@ -107,29 +107,27 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
}
esa = *(esa_info_t *)(data->enc_key.ptr);
/* only handle the case where we have both distinct ESP spi's available */
if (esa.spi_r == id->spi)
/* only handle the case where we have both distinct ESP SPI's available,
* which is always the outbound SA */
if (esa.spi_l == id->spi)
{
chunk_free(&esa.nonce_i);
chunk_free(&esa.nonce_r);
return SUCCESS;
}
spi_loc = esa.spi_l;
spi_rem = id->spi;
local = id->src;
peer = id->dst;
if (data->initiator)
{
spi_loc = id->spi;
spi_rem = esa.spi_r;
local = id->dst;
peer = id->src;
nonce_loc = &esa.nonce_i;
nonce_rem = &esa.nonce_r;
}
else
{
spi_loc = esa.spi_r;
spi_rem = id->spi;
local = id->src;
peer = id->dst;
nonce_loc = &esa.nonce_r;
nonce_rem = &esa.nonce_i;
}

View File

@ -221,7 +221,7 @@ METHOD(keymat_v2_t, derive_child_keys, bool,
INIT(esa_info_i,
.isa_id = this->isa_ctx_id,
.spi_r = proposal->get_spi(proposal),
.spi_l = proposal->get_spi(proposal),
.nonce_i = chunk_clone(nonce_i),
.nonce_r = chunk_clone(nonce_r),
.is_encr_r = FALSE,
@ -230,15 +230,15 @@ METHOD(keymat_v2_t, derive_child_keys, bool,
INIT(esa_info_r,
.isa_id = this->isa_ctx_id,
.spi_r = proposal->get_spi(proposal),
.spi_l = proposal->get_spi(proposal),
.nonce_i = chunk_clone(nonce_i),
.nonce_r = chunk_clone(nonce_r),
.is_encr_r = TRUE,
.dh_id = dh_id,
);
DBG1(DBG_CHD, "passing on esa info (isa: %llu, spi_r: %x, dh_id: %llu)",
esa_info_i->isa_id, ntohl(esa_info_i->spi_r), esa_info_i->dh_id);
DBG1(DBG_CHD, "passing on esa info (isa: %llu, spi_l: %x, dh_id: %llu)",
esa_info_i->isa_id, ntohl(esa_info_i->spi_l), esa_info_i->dh_id);
/* store ESA info in encr_i/r, which is passed to add_sa */
*encr_i = chunk_create((u_char *)esa_info_i, sizeof(esa_info_t));
@ -296,6 +296,12 @@ METHOD(keymat_v2_t, get_skd, pseudo_random_function_t,
{
isa_info_t *isa_info;
if (!this->ae_ctx_id)
{
*skd = chunk_empty;
return PRF_UNDEFINED;
}
INIT(isa_info,
.parent_isa_id = this->isa_ctx_id,
.ae_id = this->ae_ctx_id,

View File

@ -49,9 +49,9 @@ struct esa_info_t {
isa_id_type isa_id;
/**
* Responder SPI of child SA.
* Local SPI of child SA.
*/
esp_spi_type spi_r;
esp_spi_type spi_l;
/**
* Initiator nonce.

View File

@ -107,7 +107,7 @@ START_TEST(test_derive_child_keys)
fail_if(!info, "encr_i does not contain esa information");
fail_if(info->isa_id != keymat->get_isa_id(keymat),
"Isa context id mismatch (encr_i)");
fail_if(info->spi_r != 42,
fail_if(info->spi_l != 42,
"SPI mismatch (encr_i)");
fail_unless(chunk_equals(info->nonce_i, nonce),
"nonce_i mismatch (encr_i)");
@ -124,7 +124,7 @@ START_TEST(test_derive_child_keys)
fail_if(!info, "encr_r does not contain esa information");
fail_if(info->isa_id != keymat->get_isa_id(keymat),
"Isa context id mismatch (encr_r)");
fail_if(info->spi_r != 42,
fail_if(info->spi_l != 42,
"SPI mismatch (encr_r)");
fail_unless(chunk_equals(info->nonce_i, nonce),
"nonce_i mismatch (encr_r)");

File diff suppressed because it is too large Load Diff