From: Stefan Berghofer Date: Tue, 23 Jul 2019 10:42:26 +0000 (+0200) Subject: charon-tkm: Delegate encryption/decryption of IKE traffic to TKM X-Git-Tag: 5.9.3dr4~13 X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=22e7900718bcc77080ac69c3f522ea4eaed178d6;p=thirdparty%2Fstrongswan.git charon-tkm: Delegate encryption/decryption of IKE traffic to TKM Co-authored-by: Tobias Brunner --- diff --git a/src/charon-tkm/src/tkm/tkm_aead.c b/src/charon-tkm/src/tkm/tkm_aead.c new file mode 100644 index 0000000000..f89d29072e --- /dev/null +++ b/src/charon-tkm/src/tkm/tkm_aead.c @@ -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 + +#include +#include +#include + +#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; +} diff --git a/src/charon-tkm/src/tkm/tkm_aead.h b/src/charon-tkm/src/tkm/tkm_aead.h new file mode 100644 index 0000000000..61aec90f5e --- /dev/null +++ b/src/charon-tkm/src/tkm/tkm_aead.h @@ -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 +#include + +/** + * 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_ @}*/ diff --git a/src/charon-tkm/src/tkm/tkm_keymat.c b/src/charon-tkm/src/tkm/tkm_keymat.c index 1107c2219d..75fb904ae8 100644 --- a/src/charon-tkm/src/tkm/tkm_keymat.c +++ b/src/charon-tkm/src/tkm/tkm_keymat.c @@ -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); diff --git a/testing/scripts/recipes/004_spark-crypto.mk b/testing/scripts/recipes/004_spark-crypto.mk new file mode 100644 index 0000000000..00965a5873 --- /dev/null +++ b/testing/scripts/recipes/004_spark-crypto.mk @@ -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 diff --git a/testing/scripts/recipes/006_tkm-rpc.mk b/testing/scripts/recipes/006_tkm-rpc.mk index ece3baa5ec..75da7153f8 100644 --- a/testing/scripts/recipes/006_tkm-rpc.mk +++ b/testing/scripts/recipes/006_tkm-rpc.mk @@ -2,7 +2,7 @@ PKG = tkm-rpc SRC = https://git.codelabs.ch/git/$(PKG).git -REV = 1235905c5c6fad5df1eecb6ba0447d5722753203 +REV = a681aa8694412f16a44a7fba2eeb67cb3d43caf6 PREFIX = /usr/local/ada diff --git a/testing/scripts/recipes/010_tkm.mk b/testing/scripts/recipes/010_tkm.mk index 3505504204..a9e658cd81 100644 --- a/testing/scripts/recipes/010_tkm.mk +++ b/testing/scripts/recipes/010_tkm.mk @@ -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