/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#include "fd-util.h"
-#include "openssl-util.h"
#include "alloc-util.h"
+#include "fd-util.h"
#include "hexdecoct.h"
+#include "openssl-util.h"
+#include "string-util.h"
#if HAVE_OPENSSL
/* For each error in the the Openssl thread error queue, log the provided message and the Openssl error
return 0;
}
+/* Perform Key-Based HMAC KDF. The mode must be "COUNTER" or "FEEDBACK". The parameter naming is from the
+ * Openssl api, and maps to SP800-108 naming as "...key, salt, info, and seed correspond to KI, Label,
+ * Context, and IV (respectively)...". The derive_size parameter specifies how many bytes are derived.
+ *
+ * For more details see: https://www.openssl.org/docs/manmaster/man7/EVP_KDF-KB.html */
+int kdf_kb_hmac_derive(
+ const char *mode,
+ const char *digest,
+ const void *key,
+ size_t key_size,
+ const void *salt,
+ size_t salt_size,
+ const void *info,
+ size_t info_size,
+ const void *seed,
+ size_t seed_size,
+ size_t derive_size,
+ void **ret) {
+
+#if OPENSSL_VERSION_MAJOR >= 3
+ assert(mode);
+ assert(strcaseeq(mode, "COUNTER") || strcaseeq(mode, "FEEDBACK"));
+ assert(digest);
+ assert(key || key_size == 0);
+ assert(salt || salt_size == 0);
+ assert(info || info_size == 0);
+ assert(seed || seed_size == 0);
+ assert(derive_size > 0);
+ assert(ret);
+
+ _cleanup_(EVP_KDF_freep) EVP_KDF *kdf = EVP_KDF_fetch(NULL, "KBKDF", NULL);
+ if (!kdf)
+ return log_openssl_errors("Failed to create new EVP_KDF");
+
+ _cleanup_(EVP_KDF_CTX_freep) EVP_KDF_CTX *ctx = EVP_KDF_CTX_new(kdf);
+ if (!ctx)
+ return log_openssl_errors("Failed to create new EVP_KDF_CTX");
+
+ _cleanup_(OSSL_PARAM_BLD_freep) OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new();
+ if (!bld)
+ return log_openssl_errors("Failed to create new OSSL_PARAM_BLD");
+
+ if (!OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_KDF_PARAM_MAC, (char*) "HMAC", 0))
+ return log_openssl_errors("Failed to add KDF-KB OSSL_KDF_PARAM_MAC");
+
+ if (!OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_KDF_PARAM_MODE, (char*) mode, 0))
+ return log_openssl_errors("Failed to add KDF-KB OSSL_KDF_PARAM_MODE");
+
+ if (!OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_KDF_PARAM_DIGEST, (char*) digest, 0))
+ return log_openssl_errors("Failed to add KDF-KB OSSL_KDF_PARAM_DIGEST");
+
+ if (key)
+ if (!OSSL_PARAM_BLD_push_octet_string(bld, OSSL_KDF_PARAM_KEY, (char*) key, key_size))
+ return log_openssl_errors("Failed to add KDF-KB OSSL_KDF_PARAM_KEY");
+
+ if (salt)
+ if (!OSSL_PARAM_BLD_push_octet_string(bld, OSSL_KDF_PARAM_SALT, (char*) salt, salt_size))
+ return log_openssl_errors("Failed to add KDF-KB OSSL_KDF_PARAM_SALT");
+
+ if (info)
+ if (!OSSL_PARAM_BLD_push_octet_string(bld, OSSL_KDF_PARAM_INFO, (char*) info, info_size))
+ return log_openssl_errors("Failed to add KDF-KB OSSL_KDF_PARAM_INFO");
+
+ if (seed)
+ if (!OSSL_PARAM_BLD_push_octet_string(bld, OSSL_KDF_PARAM_SEED, (char*) seed, seed_size))
+ return log_openssl_errors("Failed to add KDF-KB OSSL_KDF_PARAM_SEED");
+
+ _cleanup_(OSSL_PARAM_freep) OSSL_PARAM *params = OSSL_PARAM_BLD_to_param(bld);
+ if (!params)
+ return log_openssl_errors("Failed to build KDF-KB OSSL_PARAM");
+
+ _cleanup_free_ void *buf = malloc(derive_size);
+ if (!buf)
+ return log_oom_debug();
+
+ if (EVP_KDF_derive(ctx, buf, derive_size, params) <= 0)
+ return log_openssl_errors("Openssl KDF-KB derive failed");
+
+ *ret = TAKE_PTR(buf);
+
+ return 0;
+#else
+ return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "KDF-KB requires openssl >= 3.");
+#endif
+}
+
int rsa_encrypt_bytes(
EVP_PKEY *pkey,
const void *decrypted_key,
# endif
# if OPENSSL_VERSION_MAJOR >= 3
# include <openssl/core_names.h>
+# include <openssl/kdf.h>
# include <openssl/param_build.h>
# endif
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(BIO*, BIO_free, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EVP_MD_CTX*, EVP_MD_CTX_free, NULL);
#if OPENSSL_VERSION_MAJOR >= 3
+DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EVP_KDF*, EVP_KDF_free, NULL);
+DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EVP_KDF_CTX*, EVP_KDF_CTX_free, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EVP_MAC*, EVP_MAC_free, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EVP_MAC_CTX*, EVP_MAC_CTX_free, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EVP_MD*, EVP_MD_free, NULL);
return openssl_hmac_many(digest_alg, key, key_size, &IOVEC_MAKE((void*) buf, len), 1, ret_digest, ret_digest_size);
}
+int kdf_kb_hmac_derive(const char *mode, const char *digest, const void *key, size_t key_size, const void *salt, size_t salt_size, const void *info, size_t info_size, const void *seed, size_t seed_size, size_t derive_size, void **ret);
+
int rsa_encrypt_bytes(EVP_PKEY *pkey, const void *decrypted_key, size_t decrypted_key_size, void **ret_encrypt_key, size_t *ret_encrypt_key_size);
int rsa_oaep_encrypt_bytes(const EVP_PKEY *pkey, const char *digest_alg, const char *label, const void *decrypted_key, size_t decrypted_key_size, void **ret_encrypt_key, size_t *ret_encrypt_key_size);
DEFINE_HMAC_SHA256_TEST(key3, "5BE1F4D9C2AFAA2BB3F58FCE967BC7D3084BB8F512659875BDA634991145B0F0", i1, i1, i1, i4, i4, i4, i4, i3, i3, i2);
}
+TEST(kdf_kb_hmac_derive) {
+#if OPENSSL_VERSION_MAJOR >= 3
+ _cleanup_free_ void *derived_key = NULL;
+
+ DEFINE_HEX_PTR(key, "d7ac57124f28371eacaec475b74869d26b4cd64586412a607ce0a9e0c63d468c");
+ const char *salt = "salty chocolate";
+ DEFINE_HEX_PTR(info, "6721a2012d9554f5a64593ed3eaa8fe15e6a21e1c8c8736ea4d234eb55b9e31a");
+ DEFINE_HEX_PTR(expected_derived_key, "A9DA9CEEB9578DBE7DD2862F82898B086E85FF2D10C4E8EC5BD99D0D7F003A2DE1574EB4BD789C03EF5235259BCB3A009DA303EA4DB4CA6BF507DB7C5A063279");
+
+ assert_se(kdf_kb_hmac_derive("COUNTER", "SHA256", key, key_len, salt, strlen(salt), info, info_len, /* seed= */ NULL, /* seed_size= */ 0, 64, &derived_key) >= 0);
+ assert_se(memcmp_nn(derived_key, 64, expected_derived_key, expected_derived_key_len) == 0);
+#else
+ log_tests_skipped("KDF-KB requires Openssl >= 3");
+#endif
+}
+
DEFINE_TEST_MAIN(LOG_DEBUG);