From: Tobias Brunner Date: Wed, 16 Feb 2022 15:23:38 +0000 (+0100) Subject: botan: Implement prf+ via Botan's HKDF implementation X-Git-Tag: 5.9.6rc1~2^2~10 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=cb8f92405173b07a2c8545e2202c9f32e23df22a;p=thirdparty%2Fstrongswan.git botan: Implement prf+ via Botan's HKDF implementation --- diff --git a/src/libstrongswan/plugins/botan/Makefile.am b/src/libstrongswan/plugins/botan/Makefile.am index 30d3e601c5..b7bdbdf63f 100644 --- a/src/libstrongswan/plugins/botan/Makefile.am +++ b/src/libstrongswan/plugins/botan/Makefile.am @@ -16,6 +16,7 @@ libstrongswan_botan_la_SOURCES = \ botan_rng.h botan_rng.c \ botan_hasher.h botan_hasher.c \ botan_hmac.h botan_hmac.c \ + botan_kdf.h botan_kdf.c \ botan_crypter.h botan_crypter.c \ botan_rsa_public_key.h botan_rsa_public_key.c \ botan_rsa_private_key.h botan_rsa_private_key.c \ diff --git a/src/libstrongswan/plugins/botan/botan_kdf.c b/src/libstrongswan/plugins/botan/botan_kdf.c new file mode 100644 index 0000000000..ff375851e2 --- /dev/null +++ b/src/libstrongswan/plugins/botan/botan_kdf.c @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2022 Tobias Brunner, codelabs GmbH + * + * 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. + */ + +#define _GNU_SOURCE +#include "botan_kdf.h" +#include "botan_util.h" + +#include + +#ifdef BOTAN_HAS_HKDF + +#include + +typedef struct private_kdf_t private_kdf_t; + +/** + * Private data. + */ +struct private_kdf_t { + + /** + * Public interface. + */ + kdf_t public; + + /** + * Name of the KDF algorithm in Botan. + */ + char *name; + + /** + * Key for KDF. + */ + chunk_t key; + + /** + * Salt for KDF. + */ + chunk_t salt; + +#if BOTAN_VERSION_MAJOR == 2 + /** + * Used for a manual length check in get_bytes(). + */ + size_t hash_size; +#endif +}; + +METHOD(kdf_t, get_type, key_derivation_function_t, + private_kdf_t *this) +{ + return KDF_PRF_PLUS; +} + +METHOD(kdf_t, get_bytes, bool, + private_kdf_t *this, size_t out_len, uint8_t *buffer) +{ +#if BOTAN_VERSION_MAJOR == 2 + /* Botan 2 doesn't check the length, just silently prevents wrapping the + * counter and returns truncated output, so do this manually */ + if (out_len > this->hash_size * 255) + { + return FALSE; + } +#endif + if (botan_kdf(this->name, buffer, out_len, this->key.ptr, this->key.len, + NULL, 0, this->salt.ptr, this->salt.len)) + { + return FALSE; + } + return TRUE; +} + +METHOD(kdf_t, allocate_bytes, bool, + private_kdf_t *this, size_t out_len, chunk_t *chunk) +{ + *chunk = chunk_alloc(out_len); + + if (!get_bytes(this, out_len, chunk->ptr)) + { + chunk_free(chunk); + return FALSE; + } + return TRUE; +} + +METHOD(kdf_t, set_param, bool, + private_kdf_t *this, kdf_param_t param, ...) +{ + chunk_t chunk; + + switch (param) + { + case KDF_PARAM_KEY: + VA_ARGS_GET(param, chunk); + chunk_clear(&this->key); + this->key = chunk_clone(chunk); + break; + case KDF_PARAM_SALT: + VA_ARGS_GET(param, chunk); + chunk_clear(&this->salt); + this->salt = chunk_clone(chunk); + break; + } + return TRUE; +} + +METHOD(kdf_t, destroy, void, + private_kdf_t *this) +{ + chunk_clear(&this->salt); + chunk_clear(&this->key); + free(this->name); + free(this); +} + +/* + * Described in header + */ +kdf_t *botan_kdf_create(key_derivation_function_t algo, va_list args) +{ + private_kdf_t *this; + pseudo_random_function_t prf_alg; + const char *hash_name; + char *name, buf[8]; + + if (algo != KDF_PRF_PLUS) + { + return NULL; + } + + VA_ARGS_VGET(args, prf_alg); + hash_name = botan_get_hash(hasher_algorithm_from_prf(prf_alg)); + if (!hash_name) + { + return NULL; + } + if (asprintf(&name, "HKDF-Expand(%s)", hash_name) <= 0) + { + return NULL; + } + + INIT(this, + .public = { + .get_type = _get_type, + .get_bytes = _get_bytes, + .allocate_bytes = _allocate_bytes, + .set_param = _set_param, + .destroy = _destroy, + }, + .name = name, +#if BOTAN_VERSION_MAJOR == 2 + .hash_size = hasher_hash_size(hasher_algorithm_from_prf(prf_alg)), +#endif + ); + + /* test if we can actually use the algorithm */ + if (!get_bytes(this, sizeof(buf), buf)) + { + destroy(this); + return NULL; + } + return &this->public; +} + +#endif diff --git a/src/libstrongswan/plugins/botan/botan_kdf.h b/src/libstrongswan/plugins/botan/botan_kdf.h new file mode 100644 index 0000000000..081f1d38e2 --- /dev/null +++ b/src/libstrongswan/plugins/botan/botan_kdf.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2022 Tobias Brunner, codelabs GmbH + * + * 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. + */ + +/** + * Implements key derivation functions (KDF) using Botan, in particular prf+, + * which is implemented via Botan's HKDF implementation. + * + * @defgroup botan_kdf botan_kdf + * @{ @ingroup botan_p + */ + +#ifndef BOTAN_KDF_H_ +#define BOTAN_KDF_H_ + +#include + +/** + * Creates a new kdf_t object. + * + * @param algo algorithm to instantiate + * @param args algorithm-specific arguments + * @return kdf_t object, NULL if not supported + */ +kdf_t *botan_kdf_create(key_derivation_function_t algo, va_list args); + +#endif /** BOTAN_KDF_H_ @}*/ diff --git a/src/libstrongswan/plugins/botan/botan_plugin.c b/src/libstrongswan/plugins/botan/botan_plugin.c index 41ad101ab9..d19856ad04 100644 --- a/src/libstrongswan/plugins/botan/botan_plugin.c +++ b/src/libstrongswan/plugins/botan/botan_plugin.c @@ -32,6 +32,7 @@ #include "botan_crypter.h" #include "botan_diffie_hellman.h" #include "botan_hmac.h" +#include "botan_kdf.h" #include "botan_rsa_public_key.h" #include "botan_rsa_private_key.h" #include "botan_ec_diffie_hellman.h" @@ -209,6 +210,12 @@ METHOD(plugin_t, get_features, int, #endif #endif /* BOTAN_HAS_HMAC */ + /* kdfs */ +#ifdef BOTAN_HAS_HKDF + PLUGIN_REGISTER(SIGNER, botan_kdf_create), + PLUGIN_PROVIDE(KDF, KDF_PRF_PLUS), +#endif /* BOTAN_HAS_HKDF */ + /* generic key loaders */ #if defined (BOTAN_HAS_RSA) || defined(BOTAN_HAS_ECDSA) || \ defined(BOTAN_HAS_ED25519) diff --git a/src/libstrongswan/tests/suites/test_prf_plus.c b/src/libstrongswan/tests/suites/test_prf_plus.c index cc1e47e266..d78c2612ac 100644 --- a/src/libstrongswan/tests/suites/test_prf_plus.c +++ b/src/libstrongswan/tests/suites/test_prf_plus.c @@ -137,7 +137,13 @@ START_TEST(test_wrap) /* the 1-byte counter overflows after 255 blocks of the underlying PRF */ out = chunk_alloc(32 * 255 + 1); - ck_assert(kdf->get_bytes(kdf, out.len - 1 , out.ptr)); + ck_assert(kdf->get_bytes(kdf, out.len - 2, out.ptr)); + if (!kdf->get_bytes(kdf, out.len - 1, out.ptr)) + { /* Botan 3.x has a check for (len/bs) >= 255 blocks, so we allow this */ + warn("unable to generate maximum-sized key for %N (%N) but maximum-1 " + "is fine", key_derivation_function_names, KDF_PRF_PLUS, + pseudo_random_function_names, PRF_HMAC_SHA2_256); + } ck_assert(!kdf->get_bytes(kdf, out.len, out.ptr)); chunk_free(&out); kdf->destroy(kdf); diff --git a/src/libstrongswan/utils/leak_detective.c b/src/libstrongswan/utils/leak_detective.c index 96d55f5cc1..0476353ada 100644 --- a/src/libstrongswan/utils/leak_detective.c +++ b/src/libstrongswan/utils/leak_detective.c @@ -637,6 +637,7 @@ static char *whitelist[] = { "botan_privkey_create", "botan_privkey_load_ecdh", "botan_privkey_load", + "botan_kdf", }; /** diff --git a/testing/tests/botan/net2net-ed25519/hosts/moon/etc/strongswan.conf b/testing/tests/botan/net2net-ed25519/hosts/moon/etc/strongswan.conf index 7e79f1cc0a..27954d8e2f 100755 --- a/testing/tests/botan/net2net-ed25519/hosts/moon/etc/strongswan.conf +++ b/testing/tests/botan/net2net-ed25519/hosts/moon/etc/strongswan.conf @@ -5,5 +5,5 @@ swanctl { } charon-systemd { - load = random nonce kdf pem botan x509 revocation constraints curl kernel-netlink socket-default updown vici + load = random nonce pem botan x509 revocation constraints curl kernel-netlink socket-default updown vici } diff --git a/testing/tests/botan/net2net-pkcs12/hosts/moon/etc/strongswan.conf b/testing/tests/botan/net2net-pkcs12/hosts/moon/etc/strongswan.conf index 43dc2d8236..03351e0fe0 100644 --- a/testing/tests/botan/net2net-pkcs12/hosts/moon/etc/strongswan.conf +++ b/testing/tests/botan/net2net-pkcs12/hosts/moon/etc/strongswan.conf @@ -5,5 +5,5 @@ swanctl { } charon-systemd { - load = pem nonce kdf botan x509 revocation constraints curl vici kernel-netlink socket-default updown + load = pem nonce botan x509 revocation constraints curl vici kernel-netlink socket-default updown } diff --git a/testing/tests/botan/net2net-pkcs12/hosts/sun/etc/strongswan.conf b/testing/tests/botan/net2net-pkcs12/hosts/sun/etc/strongswan.conf index 43dc2d8236..03351e0fe0 100644 --- a/testing/tests/botan/net2net-pkcs12/hosts/sun/etc/strongswan.conf +++ b/testing/tests/botan/net2net-pkcs12/hosts/sun/etc/strongswan.conf @@ -5,5 +5,5 @@ swanctl { } charon-systemd { - load = pem nonce kdf botan x509 revocation constraints curl vici kernel-netlink socket-default updown + load = pem nonce botan x509 revocation constraints curl vici kernel-netlink socket-default updown } diff --git a/testing/tests/botan/net2net-sha3-rsa-cert/hosts/moon/etc/strongswan.conf b/testing/tests/botan/net2net-sha3-rsa-cert/hosts/moon/etc/strongswan.conf index 7a4591336e..51a7747d7e 100755 --- a/testing/tests/botan/net2net-sha3-rsa-cert/hosts/moon/etc/strongswan.conf +++ b/testing/tests/botan/net2net-sha3-rsa-cert/hosts/moon/etc/strongswan.conf @@ -5,5 +5,5 @@ swanctl { } charon-systemd { - load = random nonce kdf pem x509 revocation constraints pubkey botan curl kernel-netlink socket-default updown vici + load = random nonce pem x509 revocation constraints pubkey botan curl kernel-netlink socket-default updown vici } diff --git a/testing/tests/botan/net2net-sha3-rsa-cert/hosts/sun/etc/strongswan.conf b/testing/tests/botan/net2net-sha3-rsa-cert/hosts/sun/etc/strongswan.conf index 7a4591336e..51a7747d7e 100755 --- a/testing/tests/botan/net2net-sha3-rsa-cert/hosts/sun/etc/strongswan.conf +++ b/testing/tests/botan/net2net-sha3-rsa-cert/hosts/sun/etc/strongswan.conf @@ -5,5 +5,5 @@ swanctl { } charon-systemd { - load = random nonce kdf pem x509 revocation constraints pubkey botan curl kernel-netlink socket-default updown vici + load = random nonce pem x509 revocation constraints pubkey botan curl kernel-netlink socket-default updown vici } diff --git a/testing/tests/botan/rw-cert/hosts/carol/etc/strongswan.conf b/testing/tests/botan/rw-cert/hosts/carol/etc/strongswan.conf index 372c687422..e5c6d88b30 100755 --- a/testing/tests/botan/rw-cert/hosts/carol/etc/strongswan.conf +++ b/testing/tests/botan/rw-cert/hosts/carol/etc/strongswan.conf @@ -5,7 +5,7 @@ swanctl { } charon-systemd { - load = nonce botan kdf pem x509 revocation constraints pubkey curl kernel-netlink socket-default updown vici + load = nonce botan pem x509 revocation constraints pubkey curl kernel-netlink socket-default updown vici rsa_pss = yes } diff --git a/testing/tests/botan/rw-cert/hosts/moon/etc/strongswan.conf b/testing/tests/botan/rw-cert/hosts/moon/etc/strongswan.conf index 13b6eee759..6a33d582bc 100755 --- a/testing/tests/botan/rw-cert/hosts/moon/etc/strongswan.conf +++ b/testing/tests/botan/rw-cert/hosts/moon/etc/strongswan.conf @@ -5,7 +5,7 @@ swanctl { } charon-systemd { - load = nonce test-vectors botan kdf pem x509 revocation constraints pubkey curl kernel-netlink socket-default updown vici + load = nonce test-vectors botan pem x509 revocation constraints pubkey curl kernel-netlink socket-default updown vici rsa_pss = yes integrity_test = yes diff --git a/testing/tests/botan/rw-ecp256/hosts/carol/etc/strongswan.conf b/testing/tests/botan/rw-ecp256/hosts/carol/etc/strongswan.conf index 372c687422..e5c6d88b30 100755 --- a/testing/tests/botan/rw-ecp256/hosts/carol/etc/strongswan.conf +++ b/testing/tests/botan/rw-ecp256/hosts/carol/etc/strongswan.conf @@ -5,7 +5,7 @@ swanctl { } charon-systemd { - load = nonce botan kdf pem x509 revocation constraints pubkey curl kernel-netlink socket-default updown vici + load = nonce botan pem x509 revocation constraints pubkey curl kernel-netlink socket-default updown vici rsa_pss = yes } diff --git a/testing/tests/botan/rw-ecp256/hosts/moon/etc/strongswan.conf b/testing/tests/botan/rw-ecp256/hosts/moon/etc/strongswan.conf index 8d5ef9facd..29b16f1073 100755 --- a/testing/tests/botan/rw-ecp256/hosts/moon/etc/strongswan.conf +++ b/testing/tests/botan/rw-ecp256/hosts/moon/etc/strongswan.conf @@ -5,7 +5,7 @@ swanctl { } charon-systemd { - load = nonce test-vectors botan kdf pem x509 revocation constraints pubkey curl kernel-netlink socket-default updown vici + load = nonce test-vectors botan pem x509 revocation constraints pubkey curl kernel-netlink socket-default updown vici rsa_pss = yes } diff --git a/testing/tests/botan/rw-modp3072/hosts/carol/etc/strongswan.conf b/testing/tests/botan/rw-modp3072/hosts/carol/etc/strongswan.conf index 372c687422..e5c6d88b30 100755 --- a/testing/tests/botan/rw-modp3072/hosts/carol/etc/strongswan.conf +++ b/testing/tests/botan/rw-modp3072/hosts/carol/etc/strongswan.conf @@ -5,7 +5,7 @@ swanctl { } charon-systemd { - load = nonce botan kdf pem x509 revocation constraints pubkey curl kernel-netlink socket-default updown vici + load = nonce botan pem x509 revocation constraints pubkey curl kernel-netlink socket-default updown vici rsa_pss = yes } diff --git a/testing/tests/botan/rw-modp3072/hosts/moon/etc/strongswan.conf b/testing/tests/botan/rw-modp3072/hosts/moon/etc/strongswan.conf index 8d5ef9facd..29b16f1073 100755 --- a/testing/tests/botan/rw-modp3072/hosts/moon/etc/strongswan.conf +++ b/testing/tests/botan/rw-modp3072/hosts/moon/etc/strongswan.conf @@ -5,7 +5,7 @@ swanctl { } charon-systemd { - load = nonce test-vectors botan kdf pem x509 revocation constraints pubkey curl kernel-netlink socket-default updown vici + load = nonce test-vectors botan pem x509 revocation constraints pubkey curl kernel-netlink socket-default updown vici rsa_pss = yes }