You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
185 lines
8.1 KiB
185 lines
8.1 KiB
7 months ago
|
From 1b6c4b7d68582bb7865405a143b6217ce9616b8d Mon Sep 17 00:00:00 2001
|
||
|
From: Dan Streetman <ddstreet@ieee.org>
|
||
|
Date: Tue, 27 Jun 2023 15:04:59 -0400
|
||
|
Subject: [PATCH] openssl: add kdf_kb_hmac_derive()
|
||
|
|
||
|
Add function to perform key-based (KB) key derivation function (KDF) using
|
||
|
hash-based message authentication code (HMAC).
|
||
|
|
||
|
Also alphabetize openssl-util.c header list, and include string-util.h.
|
||
|
|
||
|
(cherry picked from commit a65a25bec74d893881f0c452ece5111b1ab4e01b)
|
||
|
|
||
|
Related: RHEL-16182
|
||
|
---
|
||
|
src/shared/openssl-util.c | 91 ++++++++++++++++++++++++++++++++++++++-
|
||
|
src/shared/openssl-util.h | 5 +++
|
||
|
src/test/test-openssl.c | 16 +++++++
|
||
|
3 files changed, 110 insertions(+), 2 deletions(-)
|
||
|
|
||
|
diff --git a/src/shared/openssl-util.c b/src/shared/openssl-util.c
|
||
|
index 20c1885efb..9107f198cb 100644
|
||
|
--- a/src/shared/openssl-util.c
|
||
|
+++ b/src/shared/openssl-util.c
|
||
|
@@ -1,9 +1,10 @@
|
||
|
/* 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
|
||
|
@@ -236,6 +237,92 @@ int openssl_hmac_many(
|
||
|
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,
|
||
|
diff --git a/src/shared/openssl-util.h b/src/shared/openssl-util.h
|
||
|
index 5fe7ca341f..a927819932 100644
|
||
|
--- a/src/shared/openssl-util.h
|
||
|
+++ b/src/shared/openssl-util.h
|
||
|
@@ -23,6 +23,7 @@
|
||
|
# endif
|
||
|
# if OPENSSL_VERSION_MAJOR >= 3
|
||
|
# include <openssl/core_names.h>
|
||
|
+# include <openssl/kdf.h>
|
||
|
# include <openssl/param_build.h>
|
||
|
# endif
|
||
|
|
||
|
@@ -40,6 +41,8 @@ DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(SSL*, SSL_free, NULL);
|
||
|
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);
|
||
|
@@ -74,6 +77,8 @@ static inline int openssl_hmac(const char *digest_alg, const void *key, size_t k
|
||
|
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);
|
||
|
diff --git a/src/test/test-openssl.c b/src/test/test-openssl.c
|
||
|
index 676438f76d..a354b524f0 100644
|
||
|
--- a/src/test/test-openssl.c
|
||
|
+++ b/src/test/test-openssl.c
|
||
|
@@ -297,4 +297,20 @@ TEST(hmac_many) {
|
||
|
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);
|