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 its internal equivalent, which could be relevant
for KE implementations that want to ensure that the key can't be
accessed again after the key derivation.
This commit is contained in:
Tobias Brunner
2024-08-07 16:20:18 +02:00
parent ca3e6d2d14
commit d7760416d6
7 changed files with 765 additions and 250 deletions
+8 -10
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 SPIs 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;
}
+10 -4
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,
+2 -2
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.
+2 -2
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
+4 -4
View File
@@ -81,13 +81,13 @@ struct child_create_t {
void (*use_label)(child_create_t *this, sec_label_t *label);
/**
* Initially propose a specific DH group to override configuration.
* Initially propose a specific KE method to override configuration.
*
* This is used during rekeying to prefer the previously negotiated group.
* This is used during rekeying to prefer the previously negotiated method.
*
* @param dh_group DH group to use
* @param ke_method KE method to use
*/
void (*use_dh_group)(child_create_t *this, key_exchange_method_t dh_group);
void (*use_ke_method)(child_create_t *this, key_exchange_method_t ke_method);
/**
* Get the lower of the two nonces, used for rekey collisions.
+4 -4
View File
@@ -201,16 +201,16 @@ METHOD(task_t, build_i, status_t,
if (!this->child_create)
{
proposal_t *proposal;
uint16_t dh_group;
uint16_t ke_method;
this->child_create = child_create_create(this->ike_sa,
config->get_ref(config), TRUE, NULL, NULL);
proposal = this->child_sa->get_proposal(this->child_sa);
if (proposal->get_algorithm(proposal, KEY_EXCHANGE_METHOD,
&dh_group, NULL))
{ /* reuse the DH group negotiated previously */
this->child_create->use_dh_group(this->child_create, dh_group);
&ke_method, NULL))
{ /* reuse the KE method negotiated previously */
this->child_create->use_ke_method(this->child_create, ke_method);
}
}
reqid = this->child_sa->get_reqid_ref(this->child_sa);