Implement ESA rekeying with and without PFS
A child SA is being rekeyed if the esa information passed to the add_sa function contains nonces. If it also contains a valid Diffie-Hellman context id PFS is used. The fact that the encr_r encryption key is passed to add_sa in the inbound case can be used to determine if we are initiator or not by inspecting the is_encr_r flag of the esa information struct.
This commit is contained in:
parent
d303221c0b
commit
4a1529203b
|
@ -23,6 +23,7 @@
|
||||||
#include <tkm/client.h>
|
#include <tkm/client.h>
|
||||||
|
|
||||||
#include "tkm.h"
|
#include "tkm.h"
|
||||||
|
#include "tkm_utils.h"
|
||||||
#include "tkm_types.h"
|
#include "tkm_types.h"
|
||||||
#include "tkm_keymat.h"
|
#include "tkm_keymat.h"
|
||||||
#include "tkm_kernel_sad.h"
|
#include "tkm_kernel_sad.h"
|
||||||
|
@ -77,29 +78,112 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
|
||||||
u_int16_t cpi, bool encap, bool esn, bool inbound,
|
u_int16_t cpi, bool encap, bool esn, bool inbound,
|
||||||
traffic_selector_t* src_ts, traffic_selector_t* dst_ts)
|
traffic_selector_t* src_ts, traffic_selector_t* dst_ts)
|
||||||
{
|
{
|
||||||
if (!inbound)
|
if (enc_key.ptr == NULL)
|
||||||
{
|
{
|
||||||
|
DBG1(DBG_KNL, "Unable to get ESA information");
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
esa_info_t esa = *(esa_info_t *)(enc_key.ptr);
|
||||||
|
|
||||||
|
/* only handle the case where we have both distinct ESP spi's available */
|
||||||
|
if (esa.spi_r == spi)
|
||||||
|
{
|
||||||
|
chunk_free(&esa.nonce_i);
|
||||||
|
chunk_free(&esa.nonce_r);
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
const esa_info_t esa = *(esa_info_t *)(enc_key.ptr);
|
|
||||||
|
/* Initiator if encr_r is passed as enc_key to the inbound add_sa call */
|
||||||
|
const bool initiator = esa.is_encr_r && inbound;
|
||||||
|
|
||||||
|
esp_spi_type spi_loc, spi_rem;
|
||||||
|
host_t *local, *peer;
|
||||||
|
chunk_t *nonce_loc, *nonce_rem;
|
||||||
|
if (initiator)
|
||||||
|
{
|
||||||
|
spi_loc = spi;
|
||||||
|
spi_rem = esa.spi_r;
|
||||||
|
local = dst;
|
||||||
|
peer = src;
|
||||||
|
nonce_loc = &esa.nonce_i;
|
||||||
|
nonce_rem = &esa.nonce_r;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
spi_loc = esa.spi_r;
|
||||||
|
spi_rem = spi;
|
||||||
|
local = src;
|
||||||
|
peer = dst;
|
||||||
|
nonce_loc = &esa.nonce_r;
|
||||||
|
nonce_rem = &esa.nonce_i;
|
||||||
|
}
|
||||||
|
|
||||||
|
const nc_id_type nonce_loc_id = tkm->chunk_map->get_id(tkm->chunk_map,
|
||||||
|
nonce_loc);
|
||||||
|
|
||||||
const esa_id_type esa_id = tkm->idmgr->acquire_id(tkm->idmgr, TKM_CTX_ESA);
|
const esa_id_type esa_id = tkm->idmgr->acquire_id(tkm->idmgr, TKM_CTX_ESA);
|
||||||
DBG1(DBG_KNL, "adding child SA (esa: %llu, isa: %llu, esp_spi_loc: %x, "
|
if (!this->sad->insert(this->sad, esa_id, peer, local, spi_loc, protocol))
|
||||||
"esp_spi_rem: %x)", esa_id, esa.isa_id, ntohl(spi), ntohl(esa.spi_r));
|
|
||||||
if (!this->sad->insert(this->sad, esa_id, src, dst, spi, protocol))
|
|
||||||
{
|
{
|
||||||
DBG1(DBG_KNL, "unable to add entry (%llu) to SAD", esa_id);
|
DBG1(DBG_KNL, "unable to add entry (%llu) to SAD", esa_id);
|
||||||
tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_ESA, esa_id);
|
goto sad_failure;
|
||||||
return FAILED;
|
|
||||||
}
|
}
|
||||||
if (ike_esa_create_first(esa_id, esa.isa_id, 1, 1, ntohl(spi),
|
|
||||||
ntohl(esa.spi_r)) != TKM_OK)
|
/*
|
||||||
|
* creation of first CHILD SA:
|
||||||
|
* no nonce and no dh contexts because the ones from the IKE SA are re-used
|
||||||
|
*/
|
||||||
|
if (nonce_loc_id == 0 && esa.dh_id == 0)
|
||||||
{
|
{
|
||||||
DBG1(DBG_KNL, "child SA (%llu) creation failed", esa_id);
|
if (ike_esa_create_first(esa_id, esa.isa_id, 1, 1, ntohl(spi_loc),
|
||||||
this->sad->remove(this->sad, esa_id);
|
ntohl(spi_rem)) != TKM_OK)
|
||||||
tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_ESA, esa_id);
|
{
|
||||||
return FAILED;
|
DBG1(DBG_KNL, "child SA (%llu, first) creation failed", esa_id);
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
/* creation of child SA without PFS: no dh context */
|
||||||
|
else if (nonce_loc_id != 0 && esa.dh_id == 0)
|
||||||
|
{
|
||||||
|
nonce_type nc_rem;
|
||||||
|
chunk_to_sequence(nonce_rem, &nc_rem);
|
||||||
|
if (ike_esa_create_no_pfs(esa_id, esa.isa_id, 1, 1, nonce_loc_id,
|
||||||
|
nc_rem, initiator, ntohl(spi_loc),
|
||||||
|
ntohl(spi_rem)) != TKM_OK)
|
||||||
|
{
|
||||||
|
DBG1(DBG_KNL, "child SA (%llu, no PFS) creation failed", esa_id);
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_NONCE, nonce_loc_id);
|
||||||
|
}
|
||||||
|
/* creation of subsequent child SA with PFS: nonce and dh context are set */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nonce_type nc_rem;
|
||||||
|
chunk_to_sequence(nonce_rem, &nc_rem);
|
||||||
|
if (ike_esa_create(esa_id, esa.isa_id, 1, 1, esa.dh_id, nonce_loc_id,
|
||||||
|
nc_rem, initiator, ntohl(spi_loc),
|
||||||
|
ntohl(spi_rem)) != TKM_OK)
|
||||||
|
{
|
||||||
|
DBG1(DBG_KNL, "child SA (%llu) creation failed", esa_id);
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_NONCE, nonce_loc_id);
|
||||||
|
}
|
||||||
|
DBG1(DBG_KNL, "added child SA (esa: %llu, isa: %llu, esp_spi_loc: %x, "
|
||||||
|
"esp_spi_rem: %x, role: %s)", esa_id, esa.isa_id, ntohl(spi_loc),
|
||||||
|
ntohl(spi_rem), initiator ? "initiator" : "responder");
|
||||||
|
chunk_free(&esa.nonce_i);
|
||||||
|
chunk_free(&esa.nonce_r);
|
||||||
|
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
|
|
||||||
|
failure:
|
||||||
|
this->sad->remove(this->sad, esa_id);
|
||||||
|
sad_failure:
|
||||||
|
tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_ESA, esa_id);
|
||||||
|
chunk_free(&esa.nonce_i);
|
||||||
|
chunk_free(&esa.nonce_r);
|
||||||
|
return FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(kernel_ipsec_t, query_sa, status_t,
|
METHOD(kernel_ipsec_t, query_sa, status_t,
|
||||||
|
|
Loading…
Reference in New Issue