charon-tkm: Adapt to interface changes to support multiple key exchanges

Also includes ESA flags.

Co-authored-by: Tobias Brunner <tobias@strongswan.org>
This commit is contained in:
Stefan Berghofer 2021-07-29 14:25:15 +00:00 committed by Tobias Brunner
parent 301abbeaff
commit 7975a0cfa4
29 changed files with 341 additions and 196 deletions

View File

@ -37,7 +37,7 @@
#include "tkm.h"
#include "tkm_nonceg.h"
#include "tkm_diffie_hellman.h"
#include "tkm_key_exchange.h"
#include "tkm_keymat.h"
#include "tkm_listener.h"
#include "tkm_kernel_ipsec.h"
@ -318,9 +318,9 @@ int main(int argc, char *argv[])
lib->plugins->add_static_features(lib->plugins, "tkm-backend", features,
countof(features), TRUE, NULL, NULL);
if (!register_dh_mapping())
if (!register_ke_mapping())
{
DBG1(DBG_DMN, "no DH group mapping defined - aborting %s", dmn_name);
DBG1(DBG_DMN, "no KE group mapping defined - aborting %s", dmn_name);
goto deinit;
}
@ -410,7 +410,7 @@ int main(int argc, char *argv[])
lib->encoding->remove_encoder(lib->encoding, tkm_encoder_encode);
deinit:
destroy_dh_mapping();
destroy_ke_mapping();
destroy_ca_mapping();
libcharon_deinit();
tkm_deinit();

View File

@ -83,9 +83,10 @@ bool tkm_init()
}
/* get limits from tkm */
if (ike_tkm_limits(&max_requests, &limits[TKM_CTX_NONCE], &limits[TKM_CTX_DH],
if (ike_tkm_limits(&max_requests, &limits[TKM_CTX_NONCE], &limits[TKM_CTX_KE],
&limits[TKM_CTX_CC], &limits[TKM_CTX_AE],
&limits[TKM_CTX_ISA], &limits[TKM_CTX_ESA]) != TKM_OK)
&limits[TKM_CTX_ISA], &limits[TKM_CTX_ESA],
&limits[TKM_CTX_BLOB]) != TKM_OK)
{
ees_server_finalize();
tkmlib_final();

View File

@ -20,14 +20,15 @@
#include <utils/debug.h>
#include <threading/rwlock.h>
ENUM_BEGIN(tkm_context_kind_names, TKM_CTX_NONCE, TKM_CTX_ESA,
ENUM_BEGIN(tkm_context_kind_names, TKM_CTX_NONCE, TKM_CTX_BLOB,
"NONCE_CONTEXT",
"DH_CONTEXT",
"CC_CONTEXT",
"ISA_CONTEXT",
"AE_CONTEXT",
"ESA_CONTEXT");
ENUM_END(tkm_context_kind_names, TKM_CTX_ESA);
"ESA_CONTEXT",
"BLOB_CONTEXT");
ENUM_END(tkm_context_kind_names, TKM_CTX_BLOB);
typedef struct private_tkm_id_manager_t private_tkm_id_manager_t;

View File

@ -34,8 +34,8 @@ typedef enum tkm_context_kind_t tkm_context_kind_t;
enum tkm_context_kind_t {
/** Nonce context */
TKM_CTX_NONCE,
/** Diffie-Hellman context */
TKM_CTX_DH,
/** Key Exchange context */
TKM_CTX_KE,
/** Certificate chain context */
TKM_CTX_CC,
/** IKE SA context */
@ -44,6 +44,8 @@ enum tkm_context_kind_t {
TKM_CTX_AE,
/** ESP SA context */
TKM_CTX_ESA,
/** Blob context */
TKM_CTX_BLOB,
/** helper to determine the number of elements in this enum */
TKM_CTX_MAX,

View File

@ -93,6 +93,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
kernel_ipsec_add_sa_t *data)
{
esa_info_t esa;
esa_flags_type flags;
esp_spi_type spi_loc, spi_rem;
host_t *local, *peer;
chunk_t *nonce_loc, *nonce_rem;
@ -125,11 +126,13 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
{
nonce_loc = &esa.nonce_i;
nonce_rem = &esa.nonce_r;
flags = TKM_ESA_INITIATOR;
}
else
{
nonce_loc = &esa.nonce_r;
nonce_rem = &esa.nonce_i;
flags = 0;
}
esa_id = tkm->idmgr->acquire_id(tkm->idmgr, TKM_CTX_ESA);
@ -148,24 +151,24 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
/*
* creation of first CHILD SA:
* no nonce and no dh contexts because the ones from the IKE SA are re-used
* no nonce and no ke contexts because the ones from the IKE SA are re-used
*/
nonce_loc_id = tkm->chunk_map->get_id(tkm->chunk_map, nonce_loc);
if (nonce_loc_id == 0 && esa.dh_id == 0)
if (nonce_loc_id == 0 && esa.ke_ids.size == 0)
{
if (ike_esa_create_first(esa_id, esa.isa_id, data->reqid, 1, spi_loc,
spi_rem) != TKM_OK)
if (ike_esa_create_first(esa_id, esa.isa_id, data->reqid, 1, flags,
spi_loc, spi_rem) != TKM_OK)
{
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)
/* creation of child SA without PFS: no ke context */
else if (nonce_loc_id != 0 && esa.ke_ids.size == 0)
{
chunk_to_sequence(nonce_rem, &nc_rem, sizeof(nonce_type));
if (ike_esa_create_no_pfs(esa_id, esa.isa_id, data->reqid, 1,
nonce_loc_id, nc_rem, data->initiator,
nonce_loc_id, nc_rem, flags,
spi_loc, spi_rem) != TKM_OK)
{
DBG1(DBG_KNL, "child SA (%llu, no PFS) creation failed", esa_id);
@ -174,12 +177,12 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
tkm->chunk_map->remove(tkm->chunk_map, nonce_loc);
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 */
/* creation of subsequent child SA with PFS: nonce and ke context are set */
else
{
chunk_to_sequence(nonce_rem, &nc_rem, sizeof(nonce_type));
if (ike_esa_create(esa_id, esa.isa_id, data->reqid, 1, esa.dh_id,
nonce_loc_id, nc_rem, data->initiator, spi_loc,
if (ike_esa_create(esa_id, esa.isa_id, data->reqid, 1, esa.ke_ids,
nonce_loc_id, nc_rem, flags, spi_loc,
spi_rem) != TKM_OK)
{
DBG1(DBG_KNL, "child SA (%llu) creation failed", esa_id);

View File

@ -20,92 +20,110 @@
#include "tkm.h"
#include "tkm_utils.h"
#include "tkm_diffie_hellman.h"
#include "tkm_key_exchange.h"
#include <daemon.h>
#include <collections/hashtable.h>
typedef struct private_tkm_diffie_hellman_t private_tkm_diffie_hellman_t;
typedef struct private_tkm_key_exchange_t private_tkm_key_exchange_t;
static hashtable_t *group_map = NULL;
static hashtable_t *method_map = NULL;
/**
* Private data of a tkm_diffie_hellman_t object.
* Private data of a tkm_key_exchange_t object.
*/
struct private_tkm_diffie_hellman_t {
struct private_tkm_key_exchange_t {
/**
* Public tkm_diffie_hellman_t interface.
* Public tkm_key_exchange_t interface.
*/
tkm_diffie_hellman_t public;
tkm_key_exchange_t public;
/**
* Diffie-Hellman group number.
* Key exchange method identifier.
*/
key_exchange_method_t group;
key_exchange_method_t method;
/**
* Diffie-Hellman public value.
* Key exchange algorithm ID corresponding to method.
*/
dh_pubvalue_type pubvalue;
uint64_t kea_id;
/**
* Context id.
*/
dh_id_type context_id;
ke_id_type context_id;
};
METHOD(key_exchange_t, get_public_key, bool,
private_tkm_diffie_hellman_t *this, chunk_t *value)
private_tkm_key_exchange_t *this, chunk_t *value)
{
sequence_to_chunk(this->pubvalue.data, this->pubvalue.size, value);
return TRUE;
blob_id_type pubvalue_id;
blob_length_type pubvalue_length;
bool ret = FALSE;
pubvalue_id = tkm->idmgr->acquire_id(tkm->idmgr, TKM_CTX_BLOB);
if (pubvalue_id)
{
ret = ike_ke_get(this->context_id, this->kea_id, pubvalue_id,
&pubvalue_length) == TKM_OK &&
blob_to_chunk(pubvalue_id, pubvalue_length, value);
tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_BLOB, pubvalue_id);
}
return ret;
}
METHOD(key_exchange_t, get_shared_secret, bool,
private_tkm_diffie_hellman_t *this, chunk_t *secret)
private_tkm_key_exchange_t *this, chunk_t *secret)
{
*secret = chunk_empty;
return TRUE;
}
METHOD(key_exchange_t, set_public_key, bool,
private_tkm_diffie_hellman_t *this, chunk_t value)
private_tkm_key_exchange_t *this, chunk_t value)
{
dh_pubvalue_type othervalue;
blob_id_type pubvalue_id;
bool ret = FALSE;
if (!key_exchange_verify_pubkey(this->group, value) ||
value.len > sizeof(othervalue.data))
if (!key_exchange_verify_pubkey(this->method, value))
{
return FALSE;
}
othervalue.size = value.len;
memcpy(&othervalue.data, value.ptr, value.len);
return ike_dh_generate_key(this->context_id, othervalue) == TKM_OK;
pubvalue_id = tkm->idmgr->acquire_id(tkm->idmgr, TKM_CTX_BLOB);
if (pubvalue_id)
{
ret = chunk_to_blob(pubvalue_id, &value) &&
ike_ke_set(this->context_id, this->kea_id, pubvalue_id) == TKM_OK;
tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_BLOB, pubvalue_id);
}
return ret;
}
METHOD(key_exchange_t, get_method, key_exchange_method_t,
private_tkm_diffie_hellman_t *this)
private_tkm_key_exchange_t *this)
{
return this->group;
return this->method;
}
METHOD(key_exchange_t, destroy, void,
private_tkm_diffie_hellman_t *this)
private_tkm_key_exchange_t *this)
{
if (ike_dh_reset(this->context_id) != TKM_OK)
if (ike_ke_reset(this->context_id) != TKM_OK)
{
DBG1(DBG_LIB, "failed to reset DH context %d", this->context_id);
DBG1(DBG_LIB, "failed to reset KE context %d", this->context_id);
}
tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_DH, this->context_id);
tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_KE, this->context_id);
free(this);
}
METHOD(tkm_diffie_hellman_t, get_id, dh_id_type,
private_tkm_diffie_hellman_t *this)
METHOD(tkm_key_exchange_t, get_id, ke_id_type,
private_tkm_key_exchange_t *this)
{
return this->context_id;
}
@ -124,7 +142,7 @@ static bool equals(void *key, void *other_key)
/*
* Described in header.
*/
int register_dh_mapping()
int register_ke_mapping()
{
int count, i;
char *iana_id_str, *tkm_id_str;
@ -137,7 +155,7 @@ int register_dh_mapping()
(hashtable_equals_t)equals, 16);
enumerator = lib->settings->create_key_value_enumerator(lib->settings,
"%s.dh_mapping",
"%s.ke_mapping",
lib->ns);
while (enumerator->enumerate(enumerator, &iana_id_str, &tkm_id_str))
@ -153,7 +171,7 @@ int register_dh_mapping()
count = map->get_count(map);
plugin_feature_t f[count + 1];
f[0] = PLUGIN_REGISTER(KE, tkm_diffie_hellman_create);
f[0] = PLUGIN_REGISTER(KE, tkm_key_exchange_create);
i = 1;
enumerator = map->create_enumerator(map);
@ -164,12 +182,12 @@ int register_dh_mapping()
}
enumerator->destroy(enumerator);
lib->plugins->add_static_features(lib->plugins, "tkm-dh", f, countof(f),
lib->plugins->add_static_features(lib->plugins, "tkm-ke", f, countof(f),
TRUE, NULL, NULL);
if (count > 0)
{
group_map = map;
method_map = map;
}
else
{
@ -182,32 +200,33 @@ int register_dh_mapping()
/*
* Described in header.
*/
void destroy_dh_mapping()
void destroy_ke_mapping()
{
enumerator_t *enumerator;
char *key, *value;
if (group_map)
if (method_map)
{
enumerator = group_map->create_enumerator(group_map);
enumerator = method_map->create_enumerator(method_map);
while (enumerator->enumerate(enumerator, &key, &value))
{
free(key);
free(value);
}
enumerator->destroy(enumerator);
group_map->destroy(group_map);
method_map->destroy(method_map);
method_map = NULL;
}
}
/*
* Described in header.
*/
tkm_diffie_hellman_t *tkm_diffie_hellman_create(key_exchange_method_t group)
tkm_key_exchange_t *tkm_key_exchange_create(key_exchange_method_t method)
{
private_tkm_diffie_hellman_t *this;
private_tkm_key_exchange_t *this;
if (!group_map)
if (!method_map)
{
return NULL;
}
@ -223,8 +242,8 @@ tkm_diffie_hellman_t *tkm_diffie_hellman_create(key_exchange_method_t group)
},
.get_id = _get_id,
},
.group = group,
.context_id = tkm->idmgr->acquire_id(tkm->idmgr, TKM_CTX_DH),
.method = method,
.context_id = tkm->idmgr->acquire_id(tkm->idmgr, TKM_CTX_KE),
);
if (!this->context_id)
@ -233,18 +252,14 @@ tkm_diffie_hellman_t *tkm_diffie_hellman_create(key_exchange_method_t group)
return NULL;
}
uint64_t *dha_id = group_map->get(group_map, &group);
if (!dha_id)
uint64_t *kea_id_ptr = method_map->get(method_map, &method);
if (!kea_id_ptr)
{
free(this);
return NULL;
}
if (ike_dh_create(this->context_id, *dha_id, &this->pubvalue) != TKM_OK)
{
free(this);
return NULL;
}
this->kea_id = *kea_id_ptr;
return &this->public;
}

View File

@ -16,14 +16,14 @@
*/
/**
* @defgroup tkm-dh diffie hellman
* @defgroup tkm-ke key exchange
* @{ @ingroup tkm
*/
#ifndef TKM_DIFFIE_HELLMAN_H_
#define TKM_DIFFIE_HELLMAN_H_
#ifndef TKM_KEY_EXCHANGE_H_
#define TKM_KEY_EXCHANGE_H_
typedef struct tkm_diffie_hellman_t tkm_diffie_hellman_t;
typedef struct tkm_key_exchange_t tkm_key_exchange_t;
#include <library.h>
#include <tkm/types.h>
@ -31,7 +31,7 @@ typedef struct tkm_diffie_hellman_t tkm_diffie_hellman_t;
/**
* key_exchange_t implementation using the trusted key manager.
*/
struct tkm_diffie_hellman_t {
struct tkm_key_exchange_t {
/**
* Implements key_exchange_t interface.
@ -39,33 +39,33 @@ struct tkm_diffie_hellman_t {
key_exchange_t ke;
/**
* Get Diffie-Hellman context id.
* Get Key Exchange context id.
*
* @return id of this DH context.
* @return id of this KE context.
*/
dh_id_type (*get_id)(tkm_diffie_hellman_t * const this);
ke_id_type (*get_id)(tkm_key_exchange_t * const this);
};
/**
* Loads IANA DH group identifier to TKM id mapping from config and registers
* the corresponding DH features.
* Loads IANA KE method identifier to TKM id mapping from config and registers
* the corresponding KE plugin features.
*
* @return number of registered mappings
*/
int register_dh_mapping();
int register_ke_mapping();
/**
* Destroy IANA DH group identifier to TKM id mapping.
* Destroy IANA KE method identifier to TKM id mapping.
*/
void destroy_dh_mapping();
void destroy_ke_mapping();
/**
* Creates a new tkm_diffie_hellman_t object.
* Creates a new tkm_key_exchange_t object.
*
* @param group Diffie Hellman group number to use
* @return tkm_diffie_hellman_t object, NULL if not supported
* @param method Key exchange method to use
* @return tkm_key_exchange_t object, NULL if not supported
*/
tkm_diffie_hellman_t *tkm_diffie_hellman_create(key_exchange_method_t group);
tkm_key_exchange_t *tkm_key_exchange_create(key_exchange_method_t method);
#endif /** TKM_DIFFIE_HELLMAN_H_ @}*/
#endif /** TKM_KEY_EXCHANGE_H_ @}*/

View File

@ -24,7 +24,7 @@
#include "tkm.h"
#include "tkm_types.h"
#include "tkm_utils.h"
#include "tkm_diffie_hellman.h"
#include "tkm_key_exchange.h"
#include "tkm_keymat.h"
#include "tkm_aead.h"
@ -94,41 +94,50 @@ METHOD(keymat_t, create_nonce_gen, nonce_gen_t*,
return lib->crypto->create_nonce_gen(lib->crypto);
}
/**
* Concatenate the TKM KE IDs of the passed key exchanges
*/
static bool concat_ke_ids(array_t *kes, ke_ids_type *ids)
{
tkm_key_exchange_t *tkm_ke;
uint32_t i;
memset(ids, 0, sizeof(*ids));
ids->size = array_count(kes);
if (!ids->size || ids->size > 8)
{
return FALSE;
}
for (i = 0; i < ids->size; i++)
{
array_get(kes, i, &tkm_ke);
ids->data[i] = tkm_ke->get_id(tkm_ke);
}
return TRUE;
}
METHOD(keymat_v2_t, derive_ike_keys, bool,
private_tkm_keymat_t *this, proposal_t *proposal, array_t *kes,
chunk_t nonce_i, chunk_t nonce_r, ike_sa_id_t *id,
pseudo_random_function_t rekey_function, chunk_t rekey_skd)
{
uint64_t nc_id, spi_loc, spi_rem;
uint64_t nc_id = 0, spi_loc, spi_rem;
chunk_t *nonce;
tkm_diffie_hellman_t *tkm_dh;
key_exchange_t *ke;
dh_id_type dh_id;
ke_ids_type ke_ids;
nonce_type nonce_rem;
result_type res;
block_len_type block_len;
icv_len_type icv_len;
iv_len_type iv_len;
if (array_count(kes) != 1)
if (!concat_ke_ids(kes, &ke_ids))
{
DBG1(DBG_IKE, "the TKM currently only supports a single key exchange");
return FALSE;
}
/* Acquire nonce context id */
nonce = this->initiator ? &nonce_i : &nonce_r;
nc_id = tkm->chunk_map->get_id(tkm->chunk_map, nonce);
if (!nc_id)
{
DBG1(DBG_IKE, "unable to acquire context id for nonce");
return FALSE;
}
/* Get DH context id */
array_get(kes, ARRAY_HEAD, &ke);
tkm_dh = (tkm_diffie_hellman_t *)ke;
dh_id = tkm_dh->get_id(tkm_dh);
if (this->initiator)
{
@ -145,16 +154,24 @@ METHOD(keymat_v2_t, derive_ike_keys, bool,
if (rekey_function == PRF_UNDEFINED)
{
/* Acquire nonce context id */
nc_id = tkm->chunk_map->get_id(tkm->chunk_map, nonce);
if (!nc_id)
{
DBG1(DBG_IKE, "unable to acquire context id for nonce");
return FALSE;
}
this->ae_ctx_id = tkm->idmgr->acquire_id(tkm->idmgr, TKM_CTX_AE);
if (!this->ae_ctx_id)
{
DBG1(DBG_IKE, "unable to acquire ae context id");
return FALSE;
}
DBG1(DBG_IKE, "deriving IKE keys (nc: %llu, dh: %llu, spi_loc: %llx, "
"spi_rem: %llx)", nc_id, dh_id, spi_loc, spi_rem);
res = ike_isa_create(this->isa_ctx_id, this->ae_ctx_id, 1, dh_id, nc_id,
nonce_rem, this->initiator, spi_loc, spi_rem,
DBG1(DBG_IKE, "deriving IKE keys (nc: %llu, ke: %llu, spi_loc: %llx, "
"spi_rem: %llx)", nc_id, ke_ids.data[0], spi_loc, spi_rem);
res = ike_isa_create(this->isa_ctx_id, this->ae_ctx_id, 1, ke_ids.data[0],
nc_id, nonce_rem, this->initiator, spi_loc, spi_rem,
&block_len, &icv_len, &iv_len);
}
else
@ -167,41 +184,66 @@ METHOD(keymat_v2_t, derive_ike_keys, bool,
return FALSE;
}
isa_info = *((isa_info_t *)(rekey_skd.ptr));
DBG1(DBG_IKE, "deriving IKE keys (parent_isa: %llu, ae: %llu, nc: %llu,"
" dh: %llu, spi_loc: %llx, spi_rem: %llx)", isa_info.parent_isa_id,
isa_info.ae_id, nc_id, dh_id, spi_loc, spi_rem);
if (!tkm->idmgr->acquire_ref(tkm->idmgr, TKM_CTX_AE, isa_info.ae_id))
if (this->ae_ctx_id == isa_info.ae_id)
{
DBG1(DBG_IKE, "deriving IKE keys (parent_isa: %llu, ae: %llu, "
"ke: %llu, spi_loc: %llx, spi_rem: %llx)", isa_info.parent_isa_id,
isa_info.ae_id, ke_ids.data[0], spi_loc, spi_rem);
res = ike_isa_update(this->isa_ctx_id, ke_ids.data[0]);
}
else if (!(nc_id = tkm->chunk_map->get_id(tkm->chunk_map, nonce)))
{
DBG1(DBG_IKE, "unable to acquire context id for nonce");
return FALSE;
}
else if (!tkm->idmgr->acquire_ref(tkm->idmgr, TKM_CTX_AE, isa_info.ae_id))
{
DBG1(DBG_IKE, "unable to acquire reference for ae: %llu",
isa_info.ae_id);
return FALSE;
}
this->ae_ctx_id = isa_info.ae_id;
res = ike_isa_create_child(this->isa_ctx_id, isa_info.parent_isa_id, 1,
dh_id, nc_id, nonce_rem, this->initiator,
spi_loc, spi_rem, &block_len, &icv_len,
&iv_len);
else
{
DBG1(DBG_IKE, "deriving IKE keys (parent_isa: %llu, ae: %llu, nc: %llu, "
"ke: %llu, spi_loc: %llx, spi_rem: %llx)", isa_info.parent_isa_id,
isa_info.ae_id, nc_id, ke_ids.data[0], spi_loc, spi_rem);
this->ae_ctx_id = isa_info.ae_id;
res = ike_isa_create_child(this->isa_ctx_id, isa_info.parent_isa_id, 1,
ke_ids, nc_id, nonce_rem, this->initiator,
spi_loc, spi_rem, &block_len, &icv_len,
&iv_len);
}
chunk_free(&rekey_skd);
}
if (nc_id)
{
tkm->chunk_map->remove(tkm->chunk_map, nonce);
if (ike_nc_reset(nc_id) != TKM_OK)
{
DBG1(DBG_IKE, "failed to reset nonce context %llu", nc_id);
}
tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_NONCE, nc_id);
}
if (res != TKM_OK)
{
DBG1(DBG_IKE, "key derivation failed (isa: %llu)", this->isa_ctx_id);
return FALSE;
}
this->aead = tkm_aead_create(this->isa_ctx_id, block_len, icv_len, iv_len);
if (!this->aead)
{
this->aead = tkm_aead_create(this->isa_ctx_id, block_len, icv_len,
iv_len);
}
/* TODO: Add failure handler (see keymat_v2.c) */
tkm->chunk_map->remove(tkm->chunk_map, nonce);
if (ike_nc_reset(nc_id) != TKM_OK)
{
DBG1(DBG_IKE, "failed to reset nonce context %llu", nc_id);
}
tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_NONCE, nc_id);
return TRUE;
}
@ -211,12 +253,11 @@ METHOD(keymat_v2_t, derive_child_keys, bool,
chunk_t *encr_r, chunk_t *integ_r)
{
esa_info_t *esa_info_i, *esa_info_r;
dh_id_type dh_id = 0;
key_exchange_t *ke;
ke_ids_type ke_ids = {};
if (kes && array_get(kes, ARRAY_HEAD, &ke))
if (kes && !concat_ke_ids(kes, &ke_ids))
{
dh_id = ((tkm_diffie_hellman_t *)ke)->get_id((tkm_diffie_hellman_t *)ke);
return FALSE;
}
INIT(esa_info_i,
@ -225,7 +266,7 @@ METHOD(keymat_v2_t, derive_child_keys, bool,
.nonce_i = chunk_clone(nonce_i),
.nonce_r = chunk_clone(nonce_r),
.is_encr_r = FALSE,
.dh_id = dh_id,
.ke_ids = ke_ids,
);
INIT(esa_info_r,
@ -234,11 +275,12 @@ METHOD(keymat_v2_t, derive_child_keys, bool,
.nonce_i = chunk_clone(nonce_i),
.nonce_r = chunk_clone(nonce_r),
.is_encr_r = TRUE,
.dh_id = dh_id,
.ke_ids = ke_ids,
);
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);
DBG1(DBG_CHD, "passing on esa info (isa: %llu, spi_l: %x, "
"ke_id[%llu]: %llu)", esa_info_i->isa_id, ntohl(esa_info_i->spi_l),
esa_info_i->ke_ids.size, esa_info_i->ke_ids.data[0]);
/* 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));
@ -259,8 +301,20 @@ METHOD(keymat_v2_t, get_int_auth, bool,
private_tkm_keymat_t *this, bool verify, chunk_t data, chunk_t prev,
chunk_t *auth)
{
DBG1(DBG_IKE, "TKM doesn't support IntAuth calculation");
return FALSE;
blob_id_type data_id;
bool ret = FALSE;
*auth = chunk_empty;
data_id = tkm->idmgr->acquire_id(tkm->idmgr, TKM_CTX_BLOB);
if (data_id)
{
ret = chunk_to_blob(data_id, &data) &&
ike_isa_int_auth(this->isa_ctx_id, verify, data_id) == TKM_OK;
tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_BLOB, data_id);
}
return ret;
}
METHOD(keymat_v2_t, get_auth_octets, bool,

View File

@ -70,9 +70,9 @@ struct esa_info_t {
bool is_encr_r;
/**
* Diffie-Hellman context id.
* Key Exchange context ids.
*/
dh_id_type dh_id;
ke_ids_type ke_ids;
};

View File

@ -17,6 +17,9 @@
#include <utils/debug.h>
#include <tkm/client.h>
#include <tkm/constants.h>
#include "tkm_utils.h"
/* Generic variable-length sequence */
@ -52,3 +55,48 @@ void chunk_to_sequence(const chunk_t * const chunk, void *sequence,
}
memcpy(seq->data, chunk->ptr, seq->size);
}
bool blob_to_chunk(blob_id_type id, blob_length_type len, chunk_t * const chunk)
{
blob_offset_type offset = 0;
bool ret = TRUE;
*chunk = chunk_alloc(len);
while (len > 0 && ret)
{
blob_out_bytes_type blob_data;
blob_length_type slice_len = min(len, sizeof(blob_data.data));
ret = ike_blob_read(id, offset, slice_len, &blob_data) == TKM_OK;
memcpy(chunk->ptr + offset, blob_data.data, slice_len);
offset += slice_len;
len -= slice_len;
}
ike_blob_reset(id);
return ret;
}
bool chunk_to_blob(blob_id_type id, const chunk_t * const chunk)
{
blob_length_type len = chunk->len;
blob_offset_type offset = 0;
bool ret;
ret = ike_blob_create(id, len) == TKM_OK;
while (len > 0 && ret)
{
blob_in_bytes_type blob_data;
blob_length_type slice_len = min(len, sizeof(blob_data.data));
memcpy(blob_data.data, chunk->ptr + offset, slice_len);
blob_data.size = slice_len;
ret = ike_blob_write(id, offset, blob_data) == TKM_OK;
offset += slice_len;
len -= slice_len;
}
return ret;
}

View File

@ -46,4 +46,21 @@ void sequence_to_chunk(const byte_t * const first, const uint32_t len,
void chunk_to_sequence(const chunk_t * const chunk, void *sequence,
const uint32_t typelen);
/**
* Convert blob to chunk and reset the blob.
*
* @param id id of blob
* @param len length of blob
* @param chunk pointer to chunk struct
*/
bool blob_to_chunk(blob_id_type id, blob_length_type len, chunk_t * const chunk);
/**
* Convert chunk to newly created blob.
*
* @param id id of blob
* @param chunk pointer to chunk struct
*/
bool chunk_to_blob(blob_id_type id, const chunk_t * const chunk);
#endif /** TKM_UTILS_H_ @}*/

View File

@ -19,7 +19,7 @@
#include "tkm_id_manager.h"
static const tkm_limits_t limits = {125, 100, 55, 30, 200, 42};
static const tkm_limits_t limits = {125, 100, 55, 30, 200, 42, 21};
START_TEST(test_id_mgr_creation)
{

View File

@ -18,31 +18,31 @@
#include <daemon.h>
#include <tests/test_suite.h>
#include "tkm_diffie_hellman.h"
#include "tkm_key_exchange.h"
START_TEST(test_dh_creation)
START_TEST(test_ke_creation)
{
tkm_diffie_hellman_t *dh = NULL;
tkm_key_exchange_t *ke = NULL;
dh = tkm_diffie_hellman_create(MODP_768_BIT);
fail_if(dh, "MODP_768 created");
ke = tkm_key_exchange_create(MODP_768_BIT);
fail_if(ke, "MODP_768 created");
dh = tkm_diffie_hellman_create(MODP_4096_BIT);
fail_if(!dh, "MODP_4096 not created");
fail_if(!dh->get_id(dh), "Invalid context id (0)");
ke = tkm_key_exchange_create(MODP_4096_BIT);
fail_if(!ke, "MODP_4096 not created");
fail_if(!ke->get_id(ke), "Invalid context id (0)");
dh->ke.destroy(&dh->ke);
ke->ke.destroy(&ke->ke);
}
END_TEST
START_TEST(test_dh_get_my_pubvalue)
START_TEST(test_ke_get_my_pubvalue)
{
tkm_diffie_hellman_t *dh = tkm_diffie_hellman_create(MODP_4096_BIT);
fail_if(!dh, "Unable to create DH");
tkm_key_exchange_t *ke = tkm_key_exchange_create(MODP_4096_BIT);
fail_if(!ke, "Unable to create KE");
chunk_t value;
ck_assert(dh->ke.get_public_key(&dh->ke, &value));
dh->ke.destroy(&dh->ke);
ck_assert(ke->ke.get_public_key(&ke->ke, &value));
ke->ke.destroy(&ke->ke);
fail_if(value.ptr == NULL, "Pubvalue is NULL");
fail_if(value.len != 512, "Pubvalue size mismatch");
@ -51,19 +51,19 @@ START_TEST(test_dh_get_my_pubvalue)
}
END_TEST
Suite *make_diffie_hellman_tests()
Suite *make_key_exchange_tests()
{
Suite *s;
TCase *tc;
s = suite_create("Diffie-Hellman");
s = suite_create("key exchange");
tc = tcase_create("creation");
tcase_add_test(tc, test_dh_creation);
tcase_add_test(tc, test_ke_creation);
suite_add_tcase(s, tc);
tc = tcase_create("get_my_pubvalue");
tcase_add_test(tc, test_dh_get_my_pubvalue);
tcase_add_test(tc, test_ke_get_my_pubvalue);
suite_add_tcase(s, tc);
return s;

View File

@ -24,7 +24,7 @@
#include "tkm.h"
#include "tkm_nonceg.h"
#include "tkm_diffie_hellman.h"
#include "tkm_key_exchange.h"
#include "tkm_keymat.h"
#include "tkm_types.h"
@ -47,16 +47,16 @@ START_TEST(test_derive_ike_keys)
fail_unless(ng->nonce_gen.allocate_nonce(&ng->nonce_gen, 32, &nonce),
"Unable to allocate nonce");
tkm_diffie_hellman_t *dh = tkm_diffie_hellman_create(MODP_4096_BIT);
fail_if(!dh, "Unable to create DH");
tkm_key_exchange_t *ke = tkm_key_exchange_create(MODP_4096_BIT);
fail_if(!ke, "Unable to create KE");
/* Use the same pubvalue for both sides */
chunk_t pubvalue;
ck_assert(dh->ke.get_public_key(&dh->ke, &pubvalue));
ck_assert(dh->ke.set_public_key(&dh->ke, pubvalue));
ck_assert(ke->ke.get_public_key(&ke->ke, &pubvalue));
ck_assert(ke->ke.set_public_key(&ke->ke, pubvalue));
array_t *kes = NULL;
array_insert_create(&kes, ARRAY_TAIL, dh);
array_insert_create(&kes, ARRAY_TAIL, ke);
fail_unless(keymat->keymat_v2.derive_ike_keys(&keymat->keymat_v2, proposal,
kes, nonce, nonce, ike_sa_id, PRF_UNDEFINED, chunk_empty),
"Key derivation failed");
@ -73,7 +73,7 @@ START_TEST(test_derive_ike_keys)
ng->nonce_gen.destroy(&ng->nonce_gen);
proposal->destroy(proposal);
dh->ke.destroy(&dh->ke);
ke->ke.destroy(&ke->ke);
ike_sa_id->destroy(ike_sa_id);
keymat->keymat_v2.keymat.destroy(&keymat->keymat_v2.keymat);
chunk_free(&pubvalue);
@ -82,8 +82,8 @@ END_TEST
START_TEST(test_derive_child_keys)
{
tkm_diffie_hellman_t *dh = tkm_diffie_hellman_create(MODP_4096_BIT);
fail_if(!dh, "Unable to create DH object");
tkm_key_exchange_t *ke = tkm_key_exchange_create(MODP_4096_BIT);
fail_if(!ke, "Unable to create DH object");
proposal_t *proposal = proposal_create_from_string(PROTO_ESP,
"aes256-sha512-modp4096");
fail_if(!proposal, "Unable to create proposal");
@ -96,7 +96,7 @@ START_TEST(test_derive_child_keys)
chunk_t nonce = chunk_from_chars("test chunk");
array_t *kes = NULL;
array_insert_create(&kes, ARRAY_TAIL, dh);
array_insert_create(&kes, ARRAY_TAIL, ke);
fail_unless(keymat->keymat_v2.derive_child_keys(&keymat->keymat_v2, proposal,
kes, nonce, nonce, &encr_i,
&integ_i, &encr_r, &integ_r),
@ -115,8 +115,10 @@ START_TEST(test_derive_child_keys)
"nonce_r mismatch (encr_i)");
fail_if(info->is_encr_r,
"Flag is_encr_r set for encr_i");
fail_if(info->dh_id != dh->get_id(dh),
"DH context id mismatch (encr_i)");
fail_if(info->ke_ids.size != 1,
"KE context number mismatch (encr_i)");
fail_if(info->ke_ids.data[0] != ke->get_id(ke),
"KE context id mismatch (encr_i)");
chunk_free(&info->nonce_i);
chunk_free(&info->nonce_r);
@ -132,13 +134,15 @@ START_TEST(test_derive_child_keys)
"nonce_r mismatch (encr_r)");
fail_unless(info->is_encr_r,
"Flag is_encr_r set for encr_r");
fail_if(info->dh_id != dh->get_id(dh),
"DH context id mismatch (encr_i)");
fail_if(info->ke_ids.size != 1,
"KE context number mismatch (encr_i)");
fail_if(info->ke_ids.data[0] != ke->get_id(ke),
"KE context id mismatch (encr_i)");
chunk_free(&info->nonce_i);
chunk_free(&info->nonce_r);
proposal->destroy(proposal);
dh->ke.destroy(&dh->ke);
ke->ke.destroy(&ke->ke);
keymat->keymat_v2.keymat.destroy(&keymat->keymat_v2.keymat);
chunk_free(&encr_i);
chunk_free(&encr_r);

View File

@ -23,7 +23,7 @@
#include "tkm.h"
#include "tkm_nonceg.h"
#include "tkm_diffie_hellman.h"
#include "tkm_key_exchange.h"
#include "tkm_kernel_ipsec.h"
/* declare test suite constructors */
@ -75,11 +75,11 @@ static bool test_runner_init(bool init)
lib->plugins->add_static_features(lib->plugins, "tkm-tests", features,
countof(features), TRUE, NULL, NULL);
lib->settings->set_int(lib->settings, "%s.dh_mapping.%d", 1,
lib->settings->set_int(lib->settings, "%s.ke_mapping.%d", 1,
lib->ns, MODP_3072_BIT);
lib->settings->set_int(lib->settings, "%s.dh_mapping.%d", 2,
lib->settings->set_int(lib->settings, "%s.ke_mapping.%d", 2,
lib->ns, MODP_4096_BIT);
register_dh_mapping();
register_ke_mapping();
plugin_loader_add_plugindirs(BUILDDIR "/src/libstrongswan/plugins",
PLUGINS);
@ -100,7 +100,7 @@ static bool test_runner_init(bool init)
result = FALSE;
}
destroy_dh_mapping();
destroy_ke_mapping();
libcharon_deinit();
return result;
}

View File

@ -19,6 +19,6 @@ TEST_SUITE(make_id_manager_tests)
TEST_SUITE(make_chunk_map_tests)
TEST_SUITE(make_utility_tests)
TEST_SUITE_DEPEND(make_nonceg_tests, CUSTOM, "tkm")
TEST_SUITE_DEPEND(make_diffie_hellman_tests, CUSTOM, "tkm")
TEST_SUITE_DEPEND(make_key_exchange_tests, CUSTOM, "tkm")
TEST_SUITE_DEPEND(make_keymat_tests, CUSTOM, "tkm")
TEST_SUITE(make_kernel_sad_tests)

View File

@ -2,7 +2,7 @@
PKG = tkm-rpc
SRC = https://git.codelabs.ch/git/$(PKG).git
REV = 85f725c0c938cc7f8a48ed86892d6b112b858b8b
REV = v0.4
PREFIX = /usr/local/ada

View File

@ -2,7 +2,7 @@
PKG = tkm
SRC = https://git.codelabs.ch/git/$(PKG).git
REV = e46eef9f0991ba2777dcde845c2e00b8df9c72f7
REV = v0.3
export ADA_PROJECT_PATH=/usr/local/ada/lib/gnat

View File

@ -1,7 +1,7 @@
# /etc/strongswan.conf - strongSwan configuration file
charon-tkm {
dh_mapping {
ke_mapping {
15 = 1
16 = 2
}

View File

@ -1,7 +1,7 @@
# /etc/strongswan.conf - strongSwan configuration file
charon-tkm {
dh_mapping {
ke_mapping {
15 = 1
16 = 2
}

View File

@ -1,7 +1,7 @@
# /etc/strongswan.conf - strongSwan configuration file
charon-tkm {
dh_mapping {
ke_mapping {
15 = 1
16 = 2
}

View File

@ -1,7 +1,7 @@
# /etc/strongswan.conf - strongSwan configuration file
charon-tkm {
dh_mapping {
ke_mapping {
15 = 1
16 = 2
}

View File

@ -1,7 +1,7 @@
# /etc/strongswan.conf - strongSwan configuration file
charon-tkm {
dh_mapping {
ke_mapping {
15 = 1
16 = 2
}

View File

@ -1,7 +1,7 @@
# /etc/strongswan.conf - strongSwan configuration file
charon-tkm {
dh_mapping {
ke_mapping {
15 = 1
16 = 2
}

View File

@ -1,7 +1,7 @@
# /etc/strongswan.conf - strongSwan configuration file
charon-tkm {
dh_mapping {
ke_mapping {
15 = 1
16 = 2
}

View File

@ -17,7 +17,7 @@ moon::cat /tmp/tkm.log::Linked CC context 1 with CA certificate 1::YES
moon::cat /tmp/tkm.log::Certificate chain of CC context 1 is valid::YES
moon::cat /tmp/tkm.log::Authentication of ISA context 1 successful::YES
moon::cat /tmp/tkm.log::Creating first new ESA context with ID 1 (Isa 1, Sp 1, Ea 1, Initiator TRUE, spi_loc.*, spi_rem.*)::YES
moon::cat /tmp/tkm.log::Creating ESA context with ID 2 (Isa 1, Sp 1, Ea 1, Dh_Id 1, Nc_Loc_Id 1, Initiator TRUE, spi_loc.*, spi_rem.*)::YES
moon::cat /tmp/tkm.log::Creating ESA context with ID 2 (Isa 1, Sp 1, Ea 1, Ke_Id 1 #1 / 1, Nc_Loc_Id 1, Initiator TRUE, spi_loc.*, spi_rem.*)::YES
moon::cat /tmp/tkm.log::Adding ESA \[ 1, 192.168.0.1 <-> 192.168.0.2, SPI_in.*, SPI_out.*, soft 4, hard 60 \]::2
moon::cat /tmp/tkm.log::Resetting ESA context 1::YES
moon::cat /tmp/tkm.log::Deleting ESA \[ 1, 192.168.0.1 <=> 192.168.0.2, SPI_in.*, SPI_out.* \]::YES

View File

@ -3,7 +3,7 @@
charon-tkm {
# remove rekeyed inbound SA a bit quicker for the test scenario
delete_rekeyed_delay = 2
dh_mapping {
ke_mapping {
15 = 1
16 = 2
}

View File

@ -15,7 +15,7 @@ moon::cat /tmp/tkm.log::Linked CC context 1 with CA certificate 1::YES
moon::cat /tmp/tkm.log::Certificate chain of CC context 1 is valid::YES
moon::cat /tmp/tkm.log::Authentication of ISA context 1 successful::YES
moon::cat /tmp/tkm.log::Creating first new ESA context with ID 1 (Isa 1, Sp 1, Ea 1, Initiator TRUE, spi_loc.*, spi_rem.*)::YES
moon::cat /tmp/tkm.log::Creating ESA context with ID 2 (Isa 1, Sp 1, Ea 1, Dh_Id 1, Nc_Loc_Id 1, Initiator FALSE, spi_loc.*, spi_rem.*)::YES
moon::cat /tmp/tkm.log::Creating ESA context with ID 2 (Isa 1, Sp 1, Ea 1, Ke_Id 1 #1 / 1, Nc_Loc_Id 1, Initiator FALSE, spi_loc.*, spi_rem.*)::YES
moon::cat /tmp/tkm.log::Adding ESA \[ 1, 192.168.0.1 <-> 192.168.0.2, SPI_in.*, SPI_out.*, soft 30, hard 60 \]::2
moon::cat /tmp/tkm.log::Resetting ESA context 1::YES
moon::cat /tmp/tkm.log::Deleting ESA \[ 1, 192.168.0.1 <=> 192.168.0.2, SPI_in.*, SPI_out.* \]::YES

View File

@ -3,7 +3,7 @@
charon-tkm {
# remove rekeyed inbound SA a bit quicker for the test scenario
delete_rekeyed_delay = 2
dh_mapping {
ke_mapping {
15 = 1
16 = 2
}