charon-tkm: Delegate encryption/decryption of IKE traffic to TKM

Co-authored-by: Tobias Brunner <tobias@strongswan.org>
This commit is contained in:
Stefan Berghofer 2019-07-23 12:42:26 +02:00 committed by Tobias Brunner
parent 6537be9c8d
commit 22e7900718
6 changed files with 334 additions and 121 deletions

View File

@ -0,0 +1,245 @@
/*
* Copyright (C) 2020 Tobias Brunner
* HSR Hochschule fuer Technik Rapperswil
*
* Copyright (C) 2020 secunet Security Networks AG
* Copyright (C) 2020 Stefan Berghofer
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <errno.h>
#include <crypto/iv/iv_gen.h>
#include <tkm/constants.h>
#include <tkm/client.h>
#include "tkm_aead.h"
#include "tkm_utils.h"
typedef struct private_aead_t private_aead_t;
/**
* AEAD implementation using TKM
*/
struct private_aead_t {
/**
* Public interface
* */
aead_t public;
/**
* Internal IV generator for TKM
*/
iv_gen_t iv_gen;
/**
* ISA context id
*/
isa_id_type isa_ctx_id;
/**
* Block length of encryption algorithm
*/
block_len_type block_len;
/**
* Length of integrity check value
*/
icv_len_type icv_len;
/**
* Length of initialization vector
*/
iv_len_type iv_len;
};
METHOD(iv_gen_t, get_iv, bool,
iv_gen_t *this, uint64_t seq, size_t size, uint8_t *buffer)
{
return TRUE;
}
METHOD(iv_gen_t, allocate_iv, bool,
iv_gen_t *this, uint64_t seq, size_t size, chunk_t *chunk)
{
*chunk = chunk_alloc(size);
return get_iv(this, seq, chunk->len, chunk->ptr);
}
METHOD(aead_t, encrypt, bool,
private_aead_t *this, chunk_t plain, chunk_t assoc,
chunk_t iv, chunk_t *encrypted)
{
aad_plain_type aad_plain;
iv_encrypted_icv_type iv_encrypted_icv;
result_type res;
aad_plain = (aad_plain_type){
.size = assoc.len + plain.len,
};
if (aad_plain.size > sizeof(aad_plain.data))
{
DBG1(DBG_IKE, "%u exceeds buffer size %u, encryption failed (isa: "
"%llu)", aad_plain.size, sizeof(aad_plain.data), this->isa_ctx_id);
return FALSE;
}
memcpy(aad_plain.data, assoc.ptr, assoc.len);
memcpy(aad_plain.data + assoc.len, plain.ptr, plain.len);
res = ike_isa_encrypt(this->isa_ctx_id, assoc.len, aad_plain,
&iv_encrypted_icv);
if (res != TKM_OK)
{
DBG1(DBG_IKE, "encryption failed (isa: %llu)", this->isa_ctx_id);
return FALSE;
}
if (encrypted)
{
sequence_to_chunk(iv_encrypted_icv.data, iv_encrypted_icv.size,
encrypted);
}
else
{
memcpy(plain.ptr, iv_encrypted_icv.data + iv.len,
iv_encrypted_icv.size - iv.len);
}
memcpy(iv.ptr, iv_encrypted_icv.data, iv.len);
return TRUE;
}
METHOD(aead_t, decrypt, bool,
private_aead_t *this, chunk_t encrypted, chunk_t assoc, chunk_t iv,
chunk_t *plain)
{
aad_iv_encrypted_icv_type aad_iv_encrypted_icv;
decrypted_type decrypted;
result_type res;
aad_iv_encrypted_icv = (aad_iv_encrypted_icv_type){
.size = assoc.len + iv.len + encrypted.len,
};
if (aad_iv_encrypted_icv.size > sizeof(aad_iv_encrypted_icv.data))
{
DBG1(DBG_IKE, "%u exceeds buffer size %u, decryption failed (isa: "
"%llu)", aad_iv_encrypted_icv.size,
sizeof(aad_iv_encrypted_icv.data), this->isa_ctx_id);
return FALSE;
}
memcpy(aad_iv_encrypted_icv.data, assoc.ptr, assoc.len);
memcpy(aad_iv_encrypted_icv.data + assoc.len, iv.ptr, iv.len);
memcpy(aad_iv_encrypted_icv.data + assoc.len + iv.len, encrypted.ptr,
encrypted.len);
res = ike_isa_decrypt(this->isa_ctx_id, assoc.len, aad_iv_encrypted_icv,
&decrypted);
if (res != TKM_OK)
{
DBG1(DBG_IKE, "decryption failed (isa: %llu)", this->isa_ctx_id);
return FALSE;
}
if (plain)
{
sequence_to_chunk(decrypted.data, decrypted.size, plain);
}
else
{
memcpy(encrypted.ptr, decrypted.data, decrypted.size);
}
return TRUE;
}
METHOD(aead_t, get_block_size, size_t,
private_aead_t *this)
{
return this->block_len;
}
METHOD(aead_t, get_icv_size, size_t,
private_aead_t *this)
{
return this->icv_len;
}
METHOD(aead_t, get_iv_size, size_t,
private_aead_t *this)
{
return this->iv_len;
}
METHOD(aead_t, get_iv_gen, iv_gen_t*,
private_aead_t *this)
{
return &this->iv_gen;
}
METHOD(aead_t, get_key_size, size_t,
private_aead_t *this)
{
return 1;
}
METHOD(aead_t, set_key, bool,
private_aead_t *this, chunk_t key)
{
return TRUE;
}
METHOD(aead_t, destroy, void,
private_aead_t *this)
{
free(this);
}
/*
* Described in header
*/
aead_t *tkm_aead_create(isa_id_type isa_ctx_id, block_len_type block_len,
icv_len_type icv_len, iv_len_type iv_len)
{
private_aead_t *aead;
INIT(aead,
.public = {
.encrypt = _encrypt,
.decrypt = _decrypt,
.get_block_size = _get_block_size,
.get_icv_size = _get_icv_size,
.get_iv_size = _get_iv_size,
.get_iv_gen = _get_iv_gen,
.get_key_size = _get_key_size,
.set_key = _set_key,
.destroy = _destroy,
},
.iv_gen = {
.get_iv = _get_iv,
.allocate_iv = _allocate_iv,
.destroy = (void *)nop,
},
.isa_ctx_id = isa_ctx_id,
.block_len = block_len,
.icv_len = icv_len,
.iv_len = iv_len,
);
return &aead->public;
}

View File

@ -0,0 +1,50 @@
/*
* Copyright (C) 2020 secunet Security Networks AG
* Copyright (C) 2020 Stefan Berghofer
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* @defgroup tkm-aead aead
* @{ @ingroup tkm
*/
#ifndef TKM_AEAD_H_
#define TKM_AEAD_H_
typedef struct tkm_aead_t tkm_aead_t;
#include <crypto/aead.h>
#include <tkm/types.h>
/**
* Create an AEAD implementation providing encryption and integrity protection
* using TKM.
*
* @param isa_ctx_id id of ISA context to use for encryption/decryption
* @param block_len block length of encryption algorithm
* @param icv_len length of integrity check value
* @param iv_len length of initialization vector
* @return created aead_t object
*/
aead_t *tkm_aead_create(isa_id_type isa_ctx_id, block_len_type block_len,
icv_len_type icv_len, iv_len_type iv_len);
#endif /** TKM_AEAD_H_ @}*/

View File

@ -25,6 +25,7 @@
#include "tkm_utils.h"
#include "tkm_diffie_hellman.h"
#include "tkm_keymat.h"
#include "tkm_aead.h"
typedef struct private_tkm_keymat_t private_tkm_keymat_t;
@ -44,14 +45,9 @@ struct private_tkm_keymat_t {
bool initiator;
/**
* Inbound AEAD.
* AEAD implementation.
*/
aead_t *aead_in;
/**
* Outbound AEAD.
*/
aead_t *aead_out;
aead_t *aead;
/**
* ISA context id.
@ -79,91 +75,6 @@ struct private_tkm_keymat_t {
hash_algorithm_set_t *hash_algorithms;
};
/**
* Create AEAD transforms from given key chunks.
*
* @param in inbound AEAD transform to allocate, NULL if failed
* @param out outbound AEAD transform to allocate, NULL if failed
* @param sk_ai SK_ai key chunk
* @param sk_ar SK_ar key chunk
* @param sk_ei SK_ei key chunk
* @param sk_er SK_er key chunk
* @param enc_alg encryption algorithm to use
* @param int_alg integrity algorithm to use
* @param key_size encryption key size in bytes
* @param initiator TRUE if initiator
*/
static void aead_create_from_keys(aead_t **in, aead_t **out,
const chunk_t * const sk_ai, const chunk_t * const sk_ar,
const chunk_t * const sk_ei, const chunk_t * const sk_er,
const uint16_t enc_alg, const uint16_t int_alg,
const uint16_t key_size, bool initiator)
{
*in = *out = NULL;
signer_t *signer_i, *signer_r;
crypter_t *crypter_i, *crypter_r;
iv_gen_t *ivg_i, *ivg_r;
signer_i = lib->crypto->create_signer(lib->crypto, int_alg);
signer_r = lib->crypto->create_signer(lib->crypto, int_alg);
if (signer_i == NULL || signer_r == NULL)
{
DBG1(DBG_IKE, "%N %N not supported!",
transform_type_names, INTEGRITY_ALGORITHM,
integrity_algorithm_names, int_alg);
return;
}
crypter_i = lib->crypto->create_crypter(lib->crypto, enc_alg, key_size);
crypter_r = lib->crypto->create_crypter(lib->crypto, enc_alg, key_size);
if (crypter_i == NULL || crypter_r == NULL)
{
signer_i->destroy(signer_i);
signer_r->destroy(signer_r);
DBG1(DBG_IKE, "%N %N (key size %d) not supported!",
transform_type_names, ENCRYPTION_ALGORITHM,
encryption_algorithm_names, enc_alg, key_size);
return;
}
DBG4(DBG_IKE, "Sk_ai %B", sk_ai);
if (!signer_i->set_key(signer_i, *sk_ai))
{
return;
}
DBG4(DBG_IKE, "Sk_ar %B", sk_ar);
if (!signer_r->set_key(signer_r, *sk_ar))
{
return;
}
DBG4(DBG_IKE, "Sk_ei %B", sk_ei);
if (!crypter_i->set_key(crypter_i, *sk_ei))
{
return;
}
DBG4(DBG_IKE, "Sk_er %B", sk_er);
if (!crypter_r->set_key(crypter_r, *sk_er))
{
return;
}
ivg_i = iv_gen_create_for_alg(enc_alg);
ivg_r = iv_gen_create_for_alg(enc_alg);
if (!ivg_i || !ivg_r)
{
return;
}
if (initiator)
{
*in = aead_create(crypter_r, signer_r, ivg_r);
*out = aead_create(crypter_i, signer_i, ivg_i);
}
else
{
*in = aead_create(crypter_i, signer_i, ivg_i);
*out = aead_create(crypter_r, signer_r, ivg_r);
}
}
METHOD(keymat_t, get_version, ike_version_t,
private_tkm_keymat_t *this)
{
@ -189,12 +100,14 @@ METHOD(keymat_v2_t, derive_ike_keys, bool,
{
uint16_t enc_alg, int_alg, key_size;
uint64_t nc_id, spi_loc, spi_rem;
chunk_t *nonce, c_ai, c_ar, c_ei, c_er;
chunk_t *nonce;
tkm_diffie_hellman_t *tkm_dh;
dh_id_type dh_id;
nonce_type nonce_rem;
result_type res;
key_type sk_ai, sk_ar, sk_ei, sk_er;
block_len_type block_len;
icv_len_type icv_len;
iv_len_type iv_len;
/* Check encryption and integrity algorithms */
if (!proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &enc_alg,
@ -266,7 +179,7 @@ METHOD(keymat_v2_t, derive_ike_keys, bool,
"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,
&sk_ai, &sk_ar, &sk_ei, &sk_er);
&block_len, &icv_len, &iv_len);
}
else
{
@ -291,8 +204,8 @@ METHOD(keymat_v2_t, derive_ike_keys, bool,
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, &sk_ai, &sk_ar, &sk_ei,
&sk_er);
spi_loc, spi_rem, &block_len, &icv_len,
&iv_len);
chunk_free(&rekey_skd);
}
@ -302,25 +215,7 @@ METHOD(keymat_v2_t, derive_ike_keys, bool,
return FALSE;
}
sequence_to_chunk(sk_ai.data, sk_ai.size, &c_ai);
sequence_to_chunk(sk_ar.data, sk_ar.size, &c_ar);
sequence_to_chunk(sk_ei.data, sk_ei.size, &c_ei);
sequence_to_chunk(sk_er.data, sk_er.size, &c_er);
aead_create_from_keys(&this->aead_in, &this->aead_out, &c_ai, &c_ar, &c_ei,
&c_er, enc_alg, int_alg, key_size / 8,
this->initiator);
chunk_clear(&c_ai);
chunk_clear(&c_ar);
chunk_clear(&c_ei);
chunk_clear(&c_er);
if (!this->aead_in || !this->aead_out)
{
DBG1(DBG_IKE, "could not initialize AEAD transforms");
return FALSE;
}
this->aead = tkm_aead_create(this->isa_ctx_id, block_len, icv_len, iv_len);
/* TODO: Add failure handler (see keymat_v2.c) */
@ -380,7 +275,7 @@ METHOD(keymat_v2_t, derive_child_keys, bool,
METHOD(keymat_t, get_aead, aead_t*,
private_tkm_keymat_t *this, bool in)
{
return in ? this->aead_in : this->aead_out;
return this->aead;
}
METHOD(keymat_v2_t, get_auth_octets, bool,
@ -474,8 +369,7 @@ METHOD(keymat_t, destroy, void,
}
DESTROY_IF(this->hash_algorithms);
DESTROY_IF(this->aead_in);
DESTROY_IF(this->aead_out);
DESTROY_IF(this->aead);
chunk_free(&this->auth_payload);
chunk_free(&this->other_init_msg);
free(this);

View File

@ -0,0 +1,24 @@
#!/usr/bin/make
PKG = spark-crypto
SRC = https://git.codelabs.ch/spark-crypto.git
REV = c97939b6cdd5e5f19847cf8d1abb7575e1c01df7
DESTDIR = /usr/local/ada/lib/gnat
all: install
.$(PKG)-cloned:
[ -d $(PKG) ] || git clone $(SRC) $(PKG)
@touch $@
.$(PKG)-checkout-$(REV): .$(PKG)-cloned
cd $(PKG) && git fetch && git checkout $(REV)
@rm -f .$(PKG)-checkout-* && touch $@
.$(PKG)-built-$(REV): .$(PKG)-checkout-$(REV)
cd $(PKG) && make NO_SPARK=1 NO_TESTS=1 NO_APIDOC=1
@rm -f .$(PKG)-built-* && touch $@
install: .$(PKG)-built-$(REV)
cd $(PKG) && make NO_SPARK=1 NO_TESTS=1 NO_APIDOC=1 DESTDIR=$(DESTDIR) install

View File

@ -2,7 +2,7 @@
PKG = tkm-rpc
SRC = https://git.codelabs.ch/git/$(PKG).git
REV = 1235905c5c6fad5df1eecb6ba0447d5722753203
REV = a681aa8694412f16a44a7fba2eeb67cb3d43caf6
PREFIX = /usr/local/ada

View File

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